Skip to content

Commit 7b7e36e

Browse files
committed
MDEV-39240 10.6-11.4 Replication Allows Full Range for 32-bit Unsigned Timestamps
Row-based Replication did not vaidate serialized timestamps, which allows (pre-11.5) replicas to accept “negative” timestamps (between the Year 2038 limit and the 4-byte limit) via replication. In particular, a completely valid source of those timestamps is 11.5.1+ primaries, where MDEV-32188 has increased the upper limit of timestamps to Year 2106 by utilizing this previously invalid range. This commits fills in this pre-processing – swap the Year 2106 max with the Year 2038 max or error on the others.
1 parent 4e1faa3 commit 7b7e36e

6 files changed

Lines changed: 120 additions & 8 deletions

File tree

mysql-test/suite/binlog_encryption/rpl_typeconv.result

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ On_Master LONGTEXT,
1111
On_Slave LONGTEXT,
1212
Expected LONGTEXT,
1313
Compare INT,
14-
Error TEXT);
14+
Error INT2);
1515
SELECT @@global.slave_type_conversions;
1616
@@global.slave_type_conversions
1717

@@ -51,6 +51,10 @@ SET GLOBAL SLAVE_TYPE_CONVERSIONS='';
5151
# MDEV-17098 DATE <-> DATETIME
5252
#
5353
# End of MDEV-17098
54+
#
55+
# MDEV-39240 Invalid / MDEV-32188-only TIMESTAMPs
56+
#
57+
# End of MDEV-39240
5458
include/rpl_reset.inc
5559
connection slave;
5660
SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY';
@@ -67,6 +71,10 @@ SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY';
6771
# MDEV-17098 DATE <-> DATETIME
6872
#
6973
# End of MDEV-17098
74+
#
75+
# MDEV-39240 Invalid / MDEV-32188-only TIMESTAMPs
76+
#
77+
# End of MDEV-39240
7078
include/rpl_reset.inc
7179
connection slave;
7280
SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY';
@@ -83,6 +91,10 @@ SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY';
8391
# MDEV-17098 DATE <-> DATETIME
8492
#
8593
# End of MDEV-17098
94+
#
95+
# MDEV-39240 Invalid / MDEV-32188-only TIMESTAMPs
96+
#
97+
# End of MDEV-39240
8698
include/rpl_reset.inc
8799
connection slave;
88100
SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY';
@@ -99,6 +111,10 @@ SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY';
99111
# MDEV-17098 DATE <-> DATETIME
100112
#
101113
# End of MDEV-17098
114+
#
115+
# MDEV-39240 Invalid / MDEV-32188-only TIMESTAMPs
116+
#
117+
# End of MDEV-39240
102118
include/rpl_reset.inc
103119
connection slave;
104120
**** Result of conversions ****
@@ -267,6 +283,8 @@ DATE DATETIME(0) <Correct error>
267283
DATETIME(6) DATE <Correct error>
268284
DATETIME(6) DATE <Correct error>
269285
DATETIME(0) DATE <Correct error>
286+
TIMESTAMP(0) TIMESTAMP(0) <Correct value>
287+
TIMESTAMP(0) TIMESTAMP(0) <Correct error>
270288
TINYBLOB TINYBLOB ALL_NON_LOSSY <Correct value>
271289
TINYBLOB BLOB ALL_NON_LOSSY <Correct value>
272290
TINYBLOB MEDIUMBLOB ALL_NON_LOSSY <Correct value>
@@ -431,6 +449,8 @@ DATE DATETIME(0) ALL_NON_LOSSY <Correct value>
431449
DATETIME(6) DATE ALL_NON_LOSSY <Correct error>
432450
DATETIME(6) DATE ALL_NON_LOSSY <Correct error>
433451
DATETIME(0) DATE ALL_NON_LOSSY <Correct error>
452+
TIMESTAMP(0) TIMESTAMP(0) ALL_NON_LOSSY <Correct value>
453+
TIMESTAMP(0) TIMESTAMP(0) ALL_NON_LOSSY <Correct error>
434454
TINYBLOB TINYBLOB ALL_LOSSY <Correct value>
435455
TINYBLOB BLOB ALL_LOSSY <Correct error>
436456
TINYBLOB MEDIUMBLOB ALL_LOSSY <Correct error>
@@ -595,6 +615,8 @@ DATE DATETIME(0) ALL_LOSSY <Correct error>
595615
DATETIME(6) DATE ALL_LOSSY <Correct value>
596616
DATETIME(6) DATE ALL_LOSSY <Correct value>
597617
DATETIME(0) DATE ALL_LOSSY <Correct value>
618+
TIMESTAMP(0) TIMESTAMP(0) ALL_LOSSY <Correct value>
619+
TIMESTAMP(0) TIMESTAMP(0) ALL_LOSSY <Correct error>
598620
TINYBLOB TINYBLOB ALL_LOSSY,ALL_NON_LOSSY <Correct value>
599621
TINYBLOB BLOB ALL_LOSSY,ALL_NON_LOSSY <Correct value>
600622
TINYBLOB MEDIUMBLOB ALL_LOSSY,ALL_NON_LOSSY <Correct value>
@@ -759,8 +781,11 @@ DATE DATETIME(0) ALL_LOSSY,ALL_NON_LOSSY <Correct value>
759781
DATETIME(6) DATE ALL_LOSSY,ALL_NON_LOSSY <Correct value>
760782
DATETIME(6) DATE ALL_LOSSY,ALL_NON_LOSSY <Correct value>
761783
DATETIME(0) DATE ALL_LOSSY,ALL_NON_LOSSY <Correct value>
784+
TIMESTAMP(0) TIMESTAMP(0) ALL_LOSSY,ALL_NON_LOSSY <Correct value>
785+
TIMESTAMP(0) TIMESTAMP(0) ALL_LOSSY,ALL_NON_LOSSY <Correct error>
762786
DROP TABLE type_conversions;
763787
call mtr.add_suppression("Slave SQL.*Column 1 of table .test.t1. cannot be converted from type.* error.* 1677");
788+
call mtr.add_suppression("Slave: Got error.*: 1030");
764789
connection master;
765790
DROP TABLE t1;
766791
connection slave;

mysql-test/suite/rpl/include/check_type.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@ if ($can_convert) {
6060
if (!$can_convert) {
6161
connection slave;
6262
wait_for_slave_to_stop;
63-
let $error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
63+
let $error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, 1);
6464
eval INSERT INTO type_conversions SET
6565
Source = "$source_type",
6666
Target = "$target_type",
6767
Flags = @@slave_type_conversions,
6868
On_Master = $source_value,
69-
Error = "$error";
69+
Error = $error;
7070
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
7171
START SLAVE;
7272
}

mysql-test/suite/rpl/include/type_conversions.test

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# File containing different lossy and non-lossy type conversions.
2+
--source include/have_debug.inc
23

34
# Integral conversion testing, we do not reduce the test using
45
# transitivity of conversions since the implementation is not using a
@@ -1267,6 +1268,28 @@ let $source_temp_format=;
12671268
let $target_temp_format=;
12681269
--echo # End of MDEV-17098
12691270

1271+
--echo #
1272+
--echo # MDEV-39240 Invalid / MDEV-32188-only TIMESTAMPs
1273+
--echo #
1274+
--connection master
1275+
SET @save_dbug= @@GLOBAL.debug_dbug;
1276+
SET @@GLOBAL.debug_dbug= '+d,rpl_pack_simulate_negation';
1277+
let $source_type= TIMESTAMP(0);
1278+
let $target_type= TIMESTAMP(0);
1279+
1280+
let $source_value= '0000-00-00 00:00:00'; # ~0 = Y2106 Epochalypse II
1281+
let $target_value= FROM_UNIXTIME((1<<31) - 1); # Y2038 Epochalypse I
1282+
let $can_convert = 1;
1283+
source suite/rpl/include/check_type.inc;
1284+
1285+
let $source_value= FROM_UNIXTIME(1); # ~1 = not at an Epochalypse
1286+
let $can_convert = 0;
1287+
source suite/rpl/include/check_type.inc;
1288+
1289+
--connection master
1290+
SET @@GLOBAL.debug_dbug= @save_dbug;
1291+
--echo # End of MDEV-39240
1292+
12701293

12711294
--source include/rpl_reset.inc
12721295
enable_query_log;

mysql-test/suite/rpl/r/rpl_typeconv.result

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ On_Master LONGTEXT,
1111
On_Slave LONGTEXT,
1212
Expected LONGTEXT,
1313
Compare INT,
14-
Error TEXT);
14+
Error INT2);
1515
SELECT @@global.slave_type_conversions;
1616
@@global.slave_type_conversions
1717

@@ -51,6 +51,10 @@ SET GLOBAL SLAVE_TYPE_CONVERSIONS='';
5151
# MDEV-17098 DATE <-> DATETIME
5252
#
5353
# End of MDEV-17098
54+
#
55+
# MDEV-39240 Invalid / MDEV-32188-only TIMESTAMPs
56+
#
57+
# End of MDEV-39240
5458
include/rpl_reset.inc
5559
connection slave;
5660
SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY';
@@ -67,6 +71,10 @@ SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_NON_LOSSY';
6771
# MDEV-17098 DATE <-> DATETIME
6872
#
6973
# End of MDEV-17098
74+
#
75+
# MDEV-39240 Invalid / MDEV-32188-only TIMESTAMPs
76+
#
77+
# End of MDEV-39240
7078
include/rpl_reset.inc
7179
connection slave;
7280
SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY';
@@ -83,6 +91,10 @@ SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY';
8391
# MDEV-17098 DATE <-> DATETIME
8492
#
8593
# End of MDEV-17098
94+
#
95+
# MDEV-39240 Invalid / MDEV-32188-only TIMESTAMPs
96+
#
97+
# End of MDEV-39240
8698
include/rpl_reset.inc
8799
connection slave;
88100
SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY';
@@ -99,6 +111,10 @@ SET GLOBAL SLAVE_TYPE_CONVERSIONS='ALL_LOSSY,ALL_NON_LOSSY';
99111
# MDEV-17098 DATE <-> DATETIME
100112
#
101113
# End of MDEV-17098
114+
#
115+
# MDEV-39240 Invalid / MDEV-32188-only TIMESTAMPs
116+
#
117+
# End of MDEV-39240
102118
include/rpl_reset.inc
103119
connection slave;
104120
**** Result of conversions ****
@@ -267,6 +283,8 @@ DATE DATETIME(0) <Correct error>
267283
DATETIME(6) DATE <Correct error>
268284
DATETIME(6) DATE <Correct error>
269285
DATETIME(0) DATE <Correct error>
286+
TIMESTAMP(0) TIMESTAMP(0) <Correct value>
287+
TIMESTAMP(0) TIMESTAMP(0) <Correct error>
270288
TINYBLOB TINYBLOB ALL_NON_LOSSY <Correct value>
271289
TINYBLOB BLOB ALL_NON_LOSSY <Correct value>
272290
TINYBLOB MEDIUMBLOB ALL_NON_LOSSY <Correct value>
@@ -431,6 +449,8 @@ DATE DATETIME(0) ALL_NON_LOSSY <Correct value>
431449
DATETIME(6) DATE ALL_NON_LOSSY <Correct error>
432450
DATETIME(6) DATE ALL_NON_LOSSY <Correct error>
433451
DATETIME(0) DATE ALL_NON_LOSSY <Correct error>
452+
TIMESTAMP(0) TIMESTAMP(0) ALL_NON_LOSSY <Correct value>
453+
TIMESTAMP(0) TIMESTAMP(0) ALL_NON_LOSSY <Correct error>
434454
TINYBLOB TINYBLOB ALL_LOSSY <Correct value>
435455
TINYBLOB BLOB ALL_LOSSY <Correct error>
436456
TINYBLOB MEDIUMBLOB ALL_LOSSY <Correct error>
@@ -595,6 +615,8 @@ DATE DATETIME(0) ALL_LOSSY <Correct error>
595615
DATETIME(6) DATE ALL_LOSSY <Correct value>
596616
DATETIME(6) DATE ALL_LOSSY <Correct value>
597617
DATETIME(0) DATE ALL_LOSSY <Correct value>
618+
TIMESTAMP(0) TIMESTAMP(0) ALL_LOSSY <Correct value>
619+
TIMESTAMP(0) TIMESTAMP(0) ALL_LOSSY <Correct error>
598620
TINYBLOB TINYBLOB ALL_LOSSY,ALL_NON_LOSSY <Correct value>
599621
TINYBLOB BLOB ALL_LOSSY,ALL_NON_LOSSY <Correct value>
600622
TINYBLOB MEDIUMBLOB ALL_LOSSY,ALL_NON_LOSSY <Correct value>
@@ -759,8 +781,11 @@ DATE DATETIME(0) ALL_LOSSY,ALL_NON_LOSSY <Correct value>
759781
DATETIME(6) DATE ALL_LOSSY,ALL_NON_LOSSY <Correct value>
760782
DATETIME(6) DATE ALL_LOSSY,ALL_NON_LOSSY <Correct value>
761783
DATETIME(0) DATE ALL_LOSSY,ALL_NON_LOSSY <Correct value>
784+
TIMESTAMP(0) TIMESTAMP(0) ALL_LOSSY,ALL_NON_LOSSY <Correct value>
785+
TIMESTAMP(0) TIMESTAMP(0) ALL_LOSSY,ALL_NON_LOSSY <Correct error>
762786
DROP TABLE type_conversions;
763787
call mtr.add_suppression("Slave SQL.*Column 1 of table .test.t1. cannot be converted from type.* error.* 1677");
788+
call mtr.add_suppression("Slave: Got error.*: 1030");
764789
connection master;
765790
DROP TABLE t1;
766791
connection slave;

mysql-test/suite/rpl/t/rpl_typeconv.test

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ CREATE TABLE type_conversions (
1919
On_Slave LONGTEXT,
2020
Expected LONGTEXT,
2121
Compare INT,
22-
Error TEXT);
22+
Error INT2);
2323

2424
SELECT @@global.slave_type_conversions;
2525
SET GLOBAL SLAVE_TYPE_CONVERSIONS='';
@@ -60,7 +60,7 @@ disable_query_log;
6060
SELECT RPAD(Source, 15, ' ') AS Source_Type,
6161
RPAD(Target, 15, ' ') AS Target_Type,
6262
RPAD(Flags, 25, ' ') AS All_Type_Conversion_Flags,
63-
IF(Compare IS NULL AND Error IS NOT NULL, '<Correct error>',
63+
IF(Compare IS NULL AND Error, '<Correct error>',
6464
IF(Compare, '<Correct value>',
6565
CONCAT("'", On_Slave, "' != '", Expected, "'")))
6666
AS Value_On_Slave
@@ -69,6 +69,7 @@ enable_query_log;
6969
DROP TABLE type_conversions;
7070

7171
call mtr.add_suppression("Slave SQL.*Column 1 of table .test.t1. cannot be converted from type.* error.* 1677");
72+
call mtr.add_suppression("Slave: Got error.*: 1030");
7273

7374
connection master;
7475
DROP TABLE t1;

sql/rpl_record.cc

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,15 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
100100
length is stored in little-endian format, since this is the
101101
format used for the binlog.
102102
*/
103-
#if !defined DBUG_OFF && defined DBUG_TRACE
104-
const uchar *old_pack_ptr= pack_ptr;
103+
#ifndef DBUG_OFF
104+
uchar *old_pack_ptr= pack_ptr;
105105
#endif
106106
pack_ptr= field->pack(pack_ptr, field->ptr + offset,
107107
field->max_data_length());
108+
DBUG_EXECUTE_IF("rpl_pack_simulate_negation",
109+
for (uchar *byte= old_pack_ptr; byte < pack_ptr; ++byte)
110+
*byte= ~*byte;
111+
);
108112
DBUG_PRINT("debug", ("field: %s; real_type: %d, pack_ptr: %p;"
109113
" pack_ptr':%p; bytes: %d",
110114
field->field_name.str, field->real_type(),
@@ -187,6 +191,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
187191
A generic, internal, error caused the unpacking to fail.
188192
@retval HA_ERR_CORRUPT_EVENT
189193
Found error when trying to unpack fields.
194+
@retval HA_ERR_ROWS_EVENT_APPLY
195+
Found error when validating field values.
190196
*/
191197
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
192198
int
@@ -338,6 +344,38 @@ unpack_row(rpl_group_info *rgi,
338344
table->s->table_name.str);
339345
DBUG_RETURN(HA_ERR_CORRUPT_EVENT);
340346
}
347+
348+
// Validate this external data
349+
switch (f->type()) {
350+
case MYSQL_TYPE_TIMESTAMP:
351+
{
352+
ulong microseconds;
353+
my_time_t seconds= f->get_timestamp(&microseconds);
354+
if (likely(microseconds <= TIME_MAX_SECOND_PART))
355+
{
356+
if (likely(seconds >= 0 && seconds <= TIMESTAMP_MAX_VALUE))
357+
break;
358+
else if (likely(seconds == UINT_MAX32)) // They are both signed.
359+
{
360+
// Normalize MariaDB 11.5.1+ Epochalypse
361+
f->store_timestamp(TIMESTAMP_MAX_VALUE, microseconds);
362+
break;
363+
}
364+
}
365+
static const char unixtime_format[]=
366+
"FROM_UNIXTIME(%ld + %lu/1""000""000)";
367+
// + strlen("2147483648""16777215") - strlen("%ld""%lu")
368+
char unixtime[sizeof(unixtime_format) + 12];
369+
snprintf(unixtime, sizeof(unixtime), unixtime_format,
370+
seconds, microseconds);
371+
rgi->rli->report(ERROR_LEVEL, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
372+
rgi->gtid_info(), ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
373+
f->type_handler()->name().ptr(), unixtime, table->s->db.str,
374+
table->s->table_name.str, f->field_name.str, 0lu);
375+
DBUG_RETURN(HA_ERR_ROWS_EVENT_APPLY);
376+
}
377+
default:;
378+
}
341379
}
342380

343381
/*

0 commit comments

Comments
 (0)