DBZ-1143 Year adjustment configurable; test 19xx years

This commit is contained in:
Jiri Pechanec 2019-04-09 20:18:04 +02:00 committed by Gunnar Morling
parent 155e63adab
commit 9c7f181174
3 changed files with 69 additions and 29 deletions

View File

@ -92,29 +92,6 @@ protected static Temporal adjustTemporal(Temporal temporal) {
return temporal;
}
/**
* A utility method that adjusts <a href="https://dev.mysql.com/doc/refman/5.7/en/two-digit-years.html">ambiguous</a> 2-digit
* year values of YEAR type using these MySQL-specific rules:
* <ul>
* <li>Year values in the range 01-69 are converted to 2001-2069.</li>
* <li>Year values in the range 70-99 are converted to 1970-1999.</li>
* </ul>
* MySQL treats YEAR(4) the same, except that a numeric 00 inserted into YEAR(4) results in 0000 rather than 2000; to
* specify zero for YEAR(4) and have it be interpreted as 2000, specify it as a string '0' or '00'. This should be handled
* by MySQL before Debezium sees the value.
*
* @param year the year value to adjust; may not be null
* @return the possibly adjusted year number; never null
*/
protected static int adjustYear(int year) {
if (0 < year && year <= 69) {
year += 2000;
} else if (70 <= year && year <= 99) {
year += 1900;
}
return year;
}
/**
* Create a new instance that always uses UTC for the default time zone when converting values without timezone information
* to values that require timezones.
@ -411,18 +388,19 @@ protected Object convertYearToInt(Column column, Field fieldDefn, Object data) {
Object mutData = data;
if (data instanceof java.time.Year) {
// The MySQL binlog always returns a Year object ...
r.deliver(adjustYear(((java.time.Year) data).getValue()));
r.deliver(adjustTemporal(java.time.Year.of(((java.time.Year) data).getValue())).get(ChronoField.YEAR));
}
else if (data instanceof java.sql.Date) {
// MySQL JDBC driver sometimes returns a Java SQL Date object ...
r.deliver(adjustYear(((java.sql.Date) data).getYear()) + 1900);
// year from java.sql.Date is defined as number of years since 1900
r.deliver(((java.sql.Date) data).getYear() + 1900);
}
else if (data instanceof String) {
mutData = Integer.valueOf((String) data);
}
if (mutData instanceof Number) {
// MySQL JDBC driver sometimes returns a short ...
r.deliver(adjustYear(((Number) mutData).intValue()));
r.deliver(adjustTemporal(java.time.Year.of(((Number) mutData).intValue())).get(ChronoField.YEAR));
}
});
}

View File

@ -87,7 +87,16 @@ public void shouldProcessTwoAndForDigitYearsInDatabase() throws SQLException, In
" '2018-04-01',\n" +
" '18-04-01 12:34:56',\n" +
" '0018-04-01 12:34:56',\n" +
" '2018-04-01 12:34:56'\n" +
" '2018-04-01 12:34:56',\n" +
" '78',\n" +
" '0078',\n" +
" '1978',\n" +
" '78-04-01',\n" +
" '0078-04-01',\n" +
" '1978-04-01',\n" +
" '78-04-01 12:34:56',\n" +
" '0078-04-01 12:34:56',\n" +
" '1978-04-01 12:34:56'" +
");");
}
@ -128,7 +137,16 @@ public void shouldProcessTwoAndForDigitYearsInConnector() throws SQLException, I
" '2018-04-01',\n" +
" '18-04-01 12:34:56',\n" +
" '0018-04-01 12:34:56',\n" +
" '2018-04-01 12:34:56'\n" +
" '2018-04-01 12:34:56',\n" +
" '78',\n" +
" '0078',\n" +
" '1978',\n" +
" '78-04-01',\n" +
" '0078-04-01',\n" +
" '1978-04-01',\n" +
" '78-04-01 12:34:56',\n" +
" '0078-04-01 12:34:56',\n" +
" '1978-04-01 12:34:56'" +
");");
}
@ -153,6 +171,19 @@ private void assertChangeRecordByDatabase() throws InterruptedException {
Assertions.assertThat(change.getInt64("dt18")).isEqualTo(1_522_586_096_000L);
// Assert for 0018 will not work as long is able to handle only 292 years of nanos so we are underflowing
Assertions.assertThat(change.getInt64("dt2018")).isEqualTo(1_522_586_096_000L);
// YEAR does not differentiate between 0078 and 78
Assertions.assertThat(change.getInt32("y78")).isEqualTo(1978);
Assertions.assertThat(change.getInt32("y0078")).isEqualTo(1978);
Assertions.assertThat(change.getInt32("y1978")).isEqualTo(1978);
Assertions.assertThat(change.getInt32("d78")).isEqualTo(3012);
Assertions.assertThat(change.getInt32("d0078")).isEqualTo(-690948);
Assertions.assertThat(change.getInt32("d1978")).isEqualTo(3012);
Assertions.assertThat(change.getInt64("dt78")).isEqualTo(260_282_096_000L);
// Assert for 0018 will not work as long is able to handle only 292 years of nanos so we are underflowing
Assertions.assertThat(change.getInt64("dt1978")).isEqualTo(260_282_096_000L);
}
private void assertChangeRecordByConnector() throws InterruptedException {
@ -172,5 +203,18 @@ private void assertChangeRecordByConnector() throws InterruptedException {
Assertions.assertThat(change.getInt64("dt18")).isEqualTo(1_522_586_096_000L);
// Assert for 0018 will not work as long is able to handle only 292 years of nanos so we are underflowing
Assertions.assertThat(change.getInt64("dt2018")).isEqualTo(1_522_586_096_000L);
// YEAR does not differentiate between 0078 and 78
Assertions.assertThat(change.getInt32("y78")).isEqualTo(1978);
Assertions.assertThat(change.getInt32("y0078")).isEqualTo(1978);
Assertions.assertThat(change.getInt32("y1978")).isEqualTo(1978);
Assertions.assertThat(change.getInt32("d78")).isEqualTo(3012);
Assertions.assertThat(change.getInt32("d0078")).isEqualTo(3012);
Assertions.assertThat(change.getInt32("d1978")).isEqualTo(3012);
Assertions.assertThat(change.getInt64("dt78")).isEqualTo(260_282_096_000L);
// Assert for 0018 will not work as long is able to handle only 292 years of nanos so we are underflowing
Assertions.assertThat(change.getInt64("dt1978")).isEqualTo(260_282_096_000L);
}
}

View File

@ -13,6 +13,15 @@ CREATE TABLE dbz_1143_year_test (
dt18 DATETIME,
dt0018 DATETIME,
dt2018 DATETIME,
y78 YEAR,
y0078 YEAR,
y1978 YEAR,
d78 DATE,
d0078 DATE,
d1978 DATE,
dt78 DATETIME,
dt0078 DATETIME,
dt1978 DATETIME,
PRIMARY KEY (id)
) DEFAULT CHARSET=utf8;
@ -26,5 +35,14 @@ INSERT INTO dbz_1143_year_test VALUES (
'2018-04-01',
'18-04-01 12:34:56',
'0018-04-01 12:34:56',
'2018-04-01 12:34:56'
'2018-04-01 12:34:56',
'78',
'0078',
'1978',
'78-04-01',
'0078-04-01',
'1978-04-01',
'78-04-01 12:34:56',
'0078-04-01 12:34:56',
'1978-04-01 12:34:56'
);