From 647d5b243020b799fd7112a801965f5780b86349 Mon Sep 17 00:00:00 2001
From: Sergei Golubchik <serg@mariadb.org>
Date: Tue, 3 Sep 2019 15:28:32 +0200
Subject: MDEV-20079 When setting back the system time while mysqld is running,
 NOW() and UNIX_TIMESTAMP() results get stuck

typo. system_time.start wasn't updated when system_time.sec
and system_time.sec_part were.
---
 mysql-test/main/system_time_debug.result | 16 ++++++++++++++++
 mysql-test/main/system_time_debug.test   | 16 ++++++++++++++++
 mysys/my_getsystime.c                    |  2 ++
 sql/sql_class.h                          |  1 +
 4 files changed, 35 insertions(+)
 create mode 100644 mysql-test/main/system_time_debug.result
 create mode 100644 mysql-test/main/system_time_debug.test

diff --git a/mysql-test/main/system_time_debug.result b/mysql-test/main/system_time_debug.result
new file mode 100644
index 00000000000..98266f5e9d7
--- /dev/null
+++ b/mysql-test/main/system_time_debug.result
@@ -0,0 +1,16 @@
+set @old_dbug=@@debug_dbug;
+select timestampdiff(minute,now(),sysdate()) as 'must be 0', (unix_timestamp(sysdate()) - unix_timestamp()) div 60 as 'must be 0';
+must be 0	must be 0
+0	0
+set @@debug_dbug='+d,system_time_plus_one_hour';
+select timestampdiff(minute,now(),sysdate()) as 'must be 0', (unix_timestamp(sysdate()) - unix_timestamp()) div 60 as 'must be 0';
+must be 0	must be 0
+0	0
+set @@debug_dbug='+d,system_time_minus_one_hour:-d,system_time_plus_one_hour';
+select timestampdiff(minute,now(),sysdate()) as 'must be 0', (unix_timestamp(sysdate()) - unix_timestamp()) div 60 as 'must be 0';
+must be 0	must be 0
+0	0
+set @@debug_dbug=@old_dbug;
+select timestampdiff(minute,now(),sysdate()) as 'must be 0', (unix_timestamp(sysdate()) - unix_timestamp()) div 60 as 'must be 0';
+must be 0	must be 0
+0	0
diff --git a/mysql-test/main/system_time_debug.test b/mysql-test/main/system_time_debug.test
new file mode 100644
index 00000000000..040b4c3000e
--- /dev/null
+++ b/mysql-test/main/system_time_debug.test
@@ -0,0 +1,16 @@
+source include/have_debug.inc;
+#
+# MDEV-20079 When setting back the system time while mysqld is running, NOW() and UNIX_TIMESTAMP() results get stuck
+#
+set @old_dbug=@@debug_dbug;
+
+# because NOW() is taken at the beginning of the query and sysdate() is the actual
+# time when sysdate() was evaluated, they don't necessarily have to be equal.
+# but hopefully they're less than within a minute from each other.
+select timestampdiff(minute,now(),sysdate()) as 'must be 0', (unix_timestamp(sysdate()) - unix_timestamp()) div 60 as 'must be 0';
+set @@debug_dbug='+d,system_time_plus_one_hour';
+select timestampdiff(minute,now(),sysdate()) as 'must be 0', (unix_timestamp(sysdate()) - unix_timestamp()) div 60 as 'must be 0';
+set @@debug_dbug='+d,system_time_minus_one_hour:-d,system_time_plus_one_hour';
+select timestampdiff(minute,now(),sysdate()) as 'must be 0', (unix_timestamp(sysdate()) - unix_timestamp()) div 60 as 'must be 0';
+set @@debug_dbug=@old_dbug;
+select timestampdiff(minute,now(),sysdate()) as 'must be 0', (unix_timestamp(sysdate()) - unix_timestamp()) div 60 as 'must be 0';
diff --git a/mysys/my_getsystime.c b/mysys/my_getsystime.c
index 677da45ecea..18218c2e8de 100644
--- a/mysys/my_getsystime.c
+++ b/mysys/my_getsystime.c
@@ -99,6 +99,8 @@ my_hrtime_t my_hrtime()
   while (gettimeofday(&t, NULL) != 0) {}
   hrtime.val= t.tv_sec*1000000ULL + t.tv_usec;
 #endif
+  DBUG_EXECUTE_IF("system_time_plus_one_hour", hrtime.val += 3600*1000000ULL;);
+  DBUG_EXECUTE_IF("system_time_minus_one_hour", hrtime.val -= 3600*1000000ULL;);
   return hrtime;
 }
 
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 3157f19351c..9bd486a540e 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -3443,6 +3443,7 @@ private:
     {
       system_time.sec= sec;
       system_time.sec_part= sec_part;
+      system_time.start= hrtime;
     }
     else
     {
-- 
cgit v1.2.1