Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[CONJ-947] Timestamp encoding loose microsecond precision
only millisecond was saved:
Example Timestamp.valueOf("2010-01-12 01:55:13.123456") was saved like Timestamp.valueOf("2010-01-12 01:55:13.123")
  • Loading branch information
rusher committed Mar 28, 2022
1 parent 01f5a0c commit 0231bb7
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 44 deletions.
22 changes: 17 additions & 5 deletions src/main/java/org/mariadb/jdbc/plugin/codec/TimestampCodec.java
Expand Up @@ -328,22 +328,34 @@ public Timestamp decodeBinary(ReadableByteBuf buf, int length, Column column, Ca
public void encodeText(
Writer encoder, Context context, Object val, Calendar providedCal, Long maxLen)
throws IOException {
Timestamp ts = (Timestamp) val;
Calendar cal = providedCal == null ? Calendar.getInstance() : providedCal;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(cal.getTimeZone());
String dateString = sdf.format(val);
String dateString = sdf.format(ts);

encoder.writeByte('\'');
encoder.writeAscii(dateString);

int microseconds = ts.getNanos() / 1000;
if (microseconds > 0) {
if (microseconds % 1000 == 0) {
encoder.writeAscii("." + Integer.toString(microseconds / 1000 + 1000).substring(1));
} else {
encoder.writeAscii("." + Integer.toString(microseconds + 1000000).substring(1));
}
}

encoder.writeByte('\'');
}

@Override
public void encodeBinary(Writer encoder, Object value, Calendar providedCal, Long maxLength)
throws IOException {
Calendar cal = providedCal == null ? Calendar.getInstance() : providedCal;
cal.setTimeInMillis(((Timestamp) value).getTime());
if (cal.get(Calendar.MILLISECOND) == 0) {
Timestamp ts = (Timestamp) value;
cal.setTimeInMillis(ts.getTime());
if (ts.getNanos() == 0) {
encoder.writeByte(7); // length
encoder.writeShort((short) cal.get(Calendar.YEAR));
encoder.writeByte((cal.get(Calendar.MONTH) + 1));
Expand All @@ -359,7 +371,7 @@ public void encodeBinary(Writer encoder, Object value, Calendar providedCal, Lon
encoder.writeByte(cal.get(Calendar.HOUR_OF_DAY));
encoder.writeByte(cal.get(Calendar.MINUTE));
encoder.writeByte(cal.get(Calendar.SECOND));
encoder.writeInt(cal.get(Calendar.MILLISECOND) * 1000);
encoder.writeInt(ts.getNanos() / 1000);
}
}

Expand Down
Expand Up @@ -37,7 +37,7 @@ public static void beforeAll2() throws SQLException {
"CREATE TABLE DateTimeCodec (t1 DATETIME , t2 DATETIME(6), t3 DATETIME(6), t4 DATETIME(6))");
stmt.execute(
"INSERT INTO DateTimeCodec VALUES "
+ "('2010-01-12 01:55:12', '1000-01-01 01:55:13.2', '9999-12-31 18:30:12.55', null)"
+ "('2010-01-12 01:55:12', '1000-01-01 01:55:13.212345', '9999-12-31 18:30:12.55', null)"
+ (isMariaDBServer()
? ",('0000-00-00 00:00:00', '0000-00-00 00:00:00', '9999-12-31 00:00:00.00', null)"
: ""));
Expand Down Expand Up @@ -90,7 +90,7 @@ public void getObject(ResultSet rs) throws SQLException {
((Timestamp) rs.getObject(1)).getTime());
assertFalse(rs.wasNull());
assertEquals(
Timestamp.valueOf("1000-01-01 01:55:13.2").getTime(),
Timestamp.valueOf("1000-01-01 01:55:13.212345").getTime(),
((Timestamp) rs.getObject(2)).getTime());
assertFalse(rs.wasNull());
assertEquals(
Expand Down Expand Up @@ -154,8 +154,8 @@ public void getStringPrepare() throws SQLException {
public void getString(ResultSet rs, boolean text) throws SQLException {
assertEquals("2010-01-12 01:55:12", rs.getString(1));
assertFalse(rs.wasNull());
assertEquals("1000-01-01 01:55:13.200000", rs.getString(2));
assertEquals("1000-01-01 01:55:13.200000", rs.getString("t2alias"));
assertEquals("1000-01-01 01:55:13.212345", rs.getString(2));
assertEquals("1000-01-01 01:55:13.212345", rs.getString("t2alias"));
assertFalse(rs.wasNull());
assertEquals("9999-12-31 18:30:12.550000", rs.getString(3));
assertFalse(rs.wasNull());
Expand Down Expand Up @@ -190,9 +190,9 @@ public void getNString(ResultSet rs) throws SQLException {
assertEquals("2010-01-12 01:55:12", rs.getNString(1));
assertFalse(rs.wasNull());
String s = rs.getNString(2);
assertTrue(s.equals("1000-01-01 01:55:13.200000") || s.equals("1000-01-01 01:55:13.200"));
assertTrue(s.equals("1000-01-01 01:55:13.212345"));
s = rs.getNString("t2alias");
assertTrue(s.equals("1000-01-01 01:55:13.200000") || s.equals("1000-01-01 01:55:13.200"));
assertTrue(s.equals("1000-01-01 01:55:13.212345"));
assertFalse(rs.wasNull());
s = rs.getNString(3);
assertTrue(s.equals("9999-12-31 18:30:12.550000") || s.equals("9999-12-31 18:30:12.550"));
Expand Down Expand Up @@ -354,7 +354,8 @@ public void getDate(ResultSet rs) throws SQLException {
assertFalse(rs.wasNull());
assertEquals(
1263254400000L
- TimeZone.getDefault().getOffset(Timestamp.valueOf("2010-01-12 01:55:12").getTime()),
- TimeZone.getDefault()
.getOffset(Timestamp.valueOf("2010-01-12 01:55:12.123456").getTime()),
rs.getDate(1).getTime());
assertFalse(rs.wasNull());

Expand Down Expand Up @@ -402,9 +403,9 @@ public void getTime(ResultSet rs) throws SQLException {
assertFalse(rs.wasNull());

assertEquals(
6913200, rs.getTime(2, Calendar.getInstance(TimeZone.getTimeZone("UTC"))).getTime());
6913212, rs.getTime(2, Calendar.getInstance(TimeZone.getTimeZone("UTC"))).getTime());
assertFalse(rs.wasNull());
assertEquals(Time.valueOf("01:55:13").getTime() + 200, rs.getTime(2).getTime());
assertEquals(Time.valueOf("01:55:13").getTime() + 212, rs.getTime(2).getTime());
assertFalse(rs.wasNull());
assertEquals(Time.valueOf("18:30:12").getTime() + 550, rs.getTime(3).getTime());
assertFalse(rs.wasNull());
Expand All @@ -429,7 +430,7 @@ public void getDurationPrepare() throws SQLException {

public void getDuration(ResultSet rs) throws SQLException {
assertEquals(Duration.parse("PT265H55M12S"), rs.getObject(1, Duration.class));
assertEquals(Duration.parse("PT1H55M13.2S"), rs.getObject(2, Duration.class));
assertEquals(Duration.parse("PT1H55M13.212345S"), rs.getObject(2, Duration.class));
assertNull(rs.getObject(4, Duration.class));
if (isMariaDBServer()) {
rs.next();
Expand All @@ -451,7 +452,7 @@ public void getLocalTimePrepare() throws SQLException {
public void getLocalTime(ResultSet rs) throws SQLException {
assertEquals(LocalTime.parse("01:55:12"), rs.getObject(1, LocalTime.class));
assertFalse(rs.wasNull());
assertEquals(LocalTime.parse("01:55:13.2"), rs.getObject(2, LocalTime.class));
assertEquals(LocalTime.parse("01:55:13.212345"), rs.getObject(2, LocalTime.class));
assertFalse(rs.wasNull());
assertEquals(LocalTime.parse("18:30:12.55"), rs.getObject(3, LocalTime.class));
assertFalse(rs.wasNull());
Expand Down Expand Up @@ -505,7 +506,7 @@ public void getTimestamp(ResultSet rs) throws SQLException {
assertEquals(Timestamp.valueOf("2010-01-12 01:55:12").getTime(), rs.getTimestamp(1).getTime());
assertFalse(rs.wasNull());
assertEquals(
Timestamp.valueOf("1000-01-01 01:55:13.2").getTime(), rs.getTimestamp(2).getTime());
Timestamp.valueOf("1000-01-01 01:55:13.212345").getTime(), rs.getTimestamp(2).getTime());
assertFalse(rs.wasNull());
assertEquals(
Timestamp.valueOf("9999-12-31 18:30:12.55").getTime(), rs.getTimestamp(3).getTime());
Expand Down Expand Up @@ -738,7 +739,7 @@ private void sendParam(Connection con) throws SQLException {
prep.execute();
prep.setObject(1, null, Types.DATE);
prep.execute();
prep.setObject(1, LocalDateTime.parse("2010-01-12T01:55:12"), Types.TIMESTAMP);
prep.setObject(1, LocalDateTime.parse("2010-01-12T01:55:12.987765"), Types.TIMESTAMP);
prep.execute();
prep.setObject(1, LocalDateTime.parse("2010-01-12T01:56:12.456"), Types.TIMESTAMP);
prep.execute();
Expand Down Expand Up @@ -799,19 +800,21 @@ private void sendParam(Connection con) throws SQLException {

assertTrue(rs.next());
assertEquals(Date.valueOf("2010-01-14"), rs.getDate(2));
rs.updateObject(2, LocalDateTime.parse("2021-01-12T01:55:12"), Types.TIMESTAMP);
rs.updateObject(2, LocalDateTime.parse("2021-01-12T01:55:12.347654"), Types.TIMESTAMP);
rs.updateRow();
assertEquals(LocalDateTime.parse("2021-01-12T01:55:12"), rs.getObject(2, LocalDateTime.class));
assertEquals(
LocalDateTime.parse("2021-01-12T01:55:12.347654"), rs.getObject(2, LocalDateTime.class));
assertTrue(rs.next());
assertNull(rs.getString(2));
rs.updateTimestamp(2, Timestamp.valueOf("2015-12-12 01:55:12.654"));
rs.updateRow();
assertEquals(Timestamp.valueOf("2015-12-12 01:55:12.654"), rs.getTimestamp(2));
assertTrue(rs.next());
assertEquals(LocalDateTime.parse("2010-01-12T01:55:12"), rs.getObject(2, LocalDateTime.class));
rs.updateTimestamp("t1", Timestamp.valueOf("2015-12-12 01:55:12.654"));
assertEquals(
LocalDateTime.parse("2010-01-12T01:55:12.987765"), rs.getObject(2, LocalDateTime.class));
rs.updateTimestamp("t1", Timestamp.valueOf("2015-12-12 01:55:12.654321"));
rs.updateRow();
assertEquals(Timestamp.valueOf("2015-12-12 01:55:12.654"), rs.getTimestamp(2));
assertEquals(Timestamp.valueOf("2015-12-12 01:55:12.654321"), rs.getTimestamp(2));

rs = stmt.executeQuery("SELECT * FROM DateTimeCodec2");
assertTrue(rs.next());
Expand All @@ -823,12 +826,13 @@ private void sendParam(Connection con) throws SQLException {
assertTrue(rs.next());
assertEquals(Date.valueOf("2021-01-12"), rs.getDate(2));
assertTrue(rs.next());
assertEquals(LocalDateTime.parse("2021-01-12T01:55:12"), rs.getObject(2, LocalDateTime.class));
assertEquals(
LocalDateTime.parse("2021-01-12T01:55:12.347654"), rs.getObject(2, LocalDateTime.class));
assertTrue(rs.next());
assertEquals(Timestamp.valueOf("2015-12-12 01:55:12.654"), rs.getTimestamp(2));

assertTrue(rs.next());
assertEquals(Timestamp.valueOf("2015-12-12 01:55:12.654"), rs.getTimestamp(2));
assertEquals(Timestamp.valueOf("2015-12-12 01:55:12.654321"), rs.getTimestamp(2));
assertTrue(rs.next());
assertEquals(
LocalDateTime.parse("2010-01-12T01:56:12.456"), rs.getObject(2, LocalDateTime.class));
Expand Down
38 changes: 19 additions & 19 deletions src/test/java/org/mariadb/jdbc/integration/codec/TimeCodecTest.java
Expand Up @@ -36,7 +36,7 @@ public static void beforeAll2() throws SQLException {
stmt.execute(
"CREATE TABLE TimeCodec2 (id int not null primary key auto_increment, t1 TIME(3))");
stmt.execute(
"INSERT INTO TimeCodec VALUES ('01:55:12', '01:55:13.2', '-18:30:12.55', null), "
"INSERT INTO TimeCodec VALUES ('01:55:12', '01:55:13.234567', '-18:30:12.55', null), "
+ "('-838:59:58.999', '838:59:58.999999', '00:00:00', '00:00:00')");
}

Expand Down Expand Up @@ -85,9 +85,9 @@ public void getObject(ResultSet rs) throws SQLException {
assertFalse(rs.wasNull());

assertEquals(
6913200, rs.getTime(2, Calendar.getInstance(TimeZone.getTimeZone("UTC"))).getTime());
6913234, rs.getTime(2, Calendar.getInstance(TimeZone.getTimeZone("UTC"))).getTime());
assertFalse(rs.wasNull());
assertEquals(Time.valueOf("01:55:13").getTime() + 200, rs.getTime(2).getTime());
assertEquals(Time.valueOf("01:55:13").getTime() + 234, rs.getTime(2).getTime());
assertFalse(rs.wasNull());
assertEquals(Time.valueOf("-18:-30:-12").getTime() - 550, rs.getTime(3).getTime());
assertFalse(rs.wasNull());
Expand Down Expand Up @@ -154,8 +154,8 @@ public void getString(ResultSet rs, boolean text) throws SQLException {
// https://jira.mariadb.org/browse/XPT-273
assertEquals("01:55:12", rs.getString(1));
assertFalse(rs.wasNull());
assertEquals("01:55:13.200000", rs.getString(2));
assertEquals("01:55:13.200000", rs.getString("t2alias"));
assertEquals("01:55:13.234567", rs.getString(2));
assertEquals("01:55:13.234567", rs.getString("t2alias"));
assertFalse(rs.wasNull());
assertEquals("-18:30:12.550000", rs.getString(3));
assertFalse(rs.wasNull());
Expand All @@ -175,8 +175,8 @@ public void getString(ResultSet rs, boolean text) throws SQLException {
} else {
assertEquals("01:55:12.000", rs.getString(1));
assertFalse(rs.wasNull());
assertEquals("01:55:13.200000", rs.getString(2));
assertEquals("01:55:13.200000", rs.getString("t2alias"));
assertEquals("01:55:13.234567", rs.getString(2));
assertEquals("01:55:13.234567", rs.getString("t2alias"));
assertFalse(rs.wasNull());
assertEquals("-18:30:12.550000", rs.getString(3));
assertFalse(rs.wasNull());
Expand Down Expand Up @@ -213,8 +213,8 @@ public void getNString(ResultSet rs, boolean text) throws SQLException {
assertEquals("01:55:12.000", rs.getNString(1));
}
assertFalse(rs.wasNull());
assertEquals("01:55:13.200000", rs.getNString(2));
assertEquals("01:55:13.200000", rs.getNString("t2alias"));
assertEquals("01:55:13.234567", rs.getNString(2));
assertEquals("01:55:13.234567", rs.getNString("t2alias"));
assertFalse(rs.wasNull());
assertEquals("-18:30:12.550000", rs.getNString(3));
assertFalse(rs.wasNull());
Expand Down Expand Up @@ -387,9 +387,9 @@ public void getTime(ResultSet rs) throws SQLException {
assertFalse(rs.wasNull());

assertEquals(
6913200, rs.getTime(2, Calendar.getInstance(TimeZone.getTimeZone("UTC"))).getTime());
6913234, rs.getTime(2, Calendar.getInstance(TimeZone.getTimeZone("UTC"))).getTime());
assertFalse(rs.wasNull());
assertEquals(Time.valueOf("01:55:13").getTime() + 200, rs.getTime(2).getTime());
assertEquals(Time.valueOf("01:55:13").getTime() + 234, rs.getTime(2).getTime());
assertFalse(rs.wasNull());
assertEquals(Time.valueOf("-18:-30:-12").getTime() - 550, rs.getTime(3).getTime());
assertFalse(rs.wasNull());
Expand All @@ -411,8 +411,8 @@ public void getDurationPrepare() throws SQLException {
public void getDuration(ResultSet rs) throws SQLException {
assertEquals(Duration.parse("PT1H55M12S"), rs.getObject(1, Duration.class));
assertFalse(rs.wasNull());
assertEquals(Duration.parse("PT1H55M13.2S"), rs.getObject(2, Duration.class));
assertEquals(Duration.parse("PT1H55M13.2S"), rs.getObject("t2alias", Duration.class));
assertEquals(Duration.parse("PT1H55M13.234567S"), rs.getObject(2, Duration.class));
assertEquals(Duration.parse("PT1H55M13.234567S"), rs.getObject("t2alias", Duration.class));
assertFalse(rs.wasNull());
assertEquals(Duration.parse("PT-18H-30M-12.55S"), rs.getObject(3, Duration.class));
assertFalse(rs.wasNull());
Expand Down Expand Up @@ -444,8 +444,8 @@ public void getLocalTimePrepare() throws SQLException {
public void getLocalTime(ResultSet rs) throws SQLException {
assertEquals(LocalTime.parse("01:55:12"), rs.getObject(1, LocalTime.class));
assertFalse(rs.wasNull());
assertEquals(LocalTime.parse("01:55:13.2"), rs.getObject(2, LocalTime.class));
assertEquals(LocalTime.parse("01:55:13.2"), rs.getObject("t2alias", LocalTime.class));
assertEquals(LocalTime.parse("01:55:13.234567"), rs.getObject(2, LocalTime.class));
assertEquals(LocalTime.parse("01:55:13.234567"), rs.getObject("t2alias", LocalTime.class));
assertFalse(rs.wasNull());
// Duration.parse("PT-18H-30M-12.55S")
assertEquals(LocalTime.parse("05:29:47.450"), rs.getObject(3, LocalTime.class));
Expand Down Expand Up @@ -487,9 +487,9 @@ public void getTimestamp(ResultSet rs) throws SQLException {
assertFalse(rs.wasNull());

assertEquals(
Timestamp.valueOf("1970-01-01 01:55:13.2").getTime(), rs.getTimestamp(2).getTime());
Timestamp.valueOf("1970-01-01 01:55:13.234567").getTime(), rs.getTimestamp(2).getTime());
assertEquals(
6913200, rs.getTimestamp(2, Calendar.getInstance(TimeZone.getTimeZone("UTC"))).getTime());
6913234, rs.getTimestamp(2, Calendar.getInstance(TimeZone.getTimeZone("UTC"))).getTime());
assertFalse(rs.wasNull());
assertEquals(Timestamp.valueOf("1969-12-31 05:29:47.45"), rs.getTimestamp(3));
assertNull(rs.getTimestamp(4));
Expand Down Expand Up @@ -688,7 +688,7 @@ private void sendParam(Connection con) throws SQLException {
prep.execute();
prep.setTime(1, null);
prep.execute();
prep.setObject(1, Time.valueOf("01:55:13"));
prep.setObject(1, new Time(Time.valueOf("01:55:13").getTime() + 234));
prep.execute();
prep.setObject(1, null);
prep.execute();
Expand Down Expand Up @@ -721,7 +721,7 @@ private void sendParam(Connection con) throws SQLException {
assertEquals(tt.getTime(), rs.getTime(2).getTime());

assertTrue(rs.next());
assertEquals(Time.valueOf("01:55:13").getTime(), rs.getTime(2).getTime());
assertEquals(Time.valueOf("01:55:13").getTime() + 234, rs.getTime(2).getTime());
rs.updateObject(2, Time.valueOf("01:55:14"), JDBCType.TIME);
rs.updateRow();
assertEquals(Time.valueOf("01:55:14").getTime(), rs.getTime(2).getTime());
Expand Down

0 comments on commit 0231bb7

Please sign in to comment.