Skip to content

Commit

Permalink
[CONJ-1017] concurrent data/time/timestamp when using same calendar p…
Browse files Browse the repository at this point in the history
…arameter missing synchronization
  • Loading branch information
rusher committed Oct 10, 2022
1 parent fe6498b commit 22388e6
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 42 deletions.
13 changes: 8 additions & 5 deletions src/main/java/org/mariadb/jdbc/plugin/codec/DateCodec.java
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,14 @@ public void encodeText(
public void encodeBinary(Writer encoder, Object value, Calendar providedCal, Long maxLength)
throws IOException {
Calendar cal = providedCal == null ? Calendar.getInstance() : providedCal;
cal.setTimeInMillis(((java.util.Date) value).getTime());
encoder.writeByte(4); // length
encoder.writeShort((short) cal.get(Calendar.YEAR));
encoder.writeByte(((cal.get(Calendar.MONTH) + 1) & 0xff));
encoder.writeByte((cal.get(Calendar.DAY_OF_MONTH) & 0xff));
synchronized (cal) {
cal.clear();
cal.setTimeInMillis(((java.util.Date) value).getTime());
encoder.writeByte(4); // length
encoder.writeShort((short) cal.get(Calendar.YEAR));
encoder.writeByte(((cal.get(Calendar.MONTH) + 1) & 0xff));
encoder.writeByte((cal.get(Calendar.DAY_OF_MONTH) & 0xff));
}
}

public int getBinaryEncodeType() {
Expand Down
37 changes: 20 additions & 17 deletions src/main/java/org/mariadb/jdbc/plugin/codec/TimeCodec.java
Original file line number Diff line number Diff line change
Expand Up @@ -231,23 +231,26 @@ public void encodeText(
public void encodeBinary(Writer encoder, Object value, Calendar providedCal, Long maxLength)
throws IOException {
Calendar cal = providedCal == null ? Calendar.getInstance() : providedCal;
cal.setTime((Time) value);
cal.set(Calendar.DAY_OF_MONTH, 1);
if (cal.get(Calendar.MILLISECOND) > 0) {
encoder.writeByte((byte) 12);
encoder.writeByte((byte) 0);
encoder.writeInt(0);
encoder.writeByte((byte) cal.get(Calendar.HOUR_OF_DAY));
encoder.writeByte((byte) cal.get(Calendar.MINUTE));
encoder.writeByte((byte) cal.get(Calendar.SECOND));
encoder.writeInt(cal.get(Calendar.MILLISECOND) * 1000);
} else {
encoder.writeByte((byte) 8); // length
encoder.writeByte((byte) 0);
encoder.writeInt(0);
encoder.writeByte((byte) cal.get(Calendar.HOUR_OF_DAY));
encoder.writeByte((byte) cal.get(Calendar.MINUTE));
encoder.writeByte((byte) cal.get(Calendar.SECOND));
synchronized (cal) {
cal.clear();
cal.setTime((Time) value);
cal.set(Calendar.DAY_OF_MONTH, 1);
if (cal.get(Calendar.MILLISECOND) > 0) {
encoder.writeByte((byte) 12);
encoder.writeByte((byte) 0);
encoder.writeInt(0);
encoder.writeByte((byte) cal.get(Calendar.HOUR_OF_DAY));
encoder.writeByte((byte) cal.get(Calendar.MINUTE));
encoder.writeByte((byte) cal.get(Calendar.SECOND));
encoder.writeInt(cal.get(Calendar.MILLISECOND) * 1000);
} else {
encoder.writeByte((byte) 8); // length
encoder.writeByte((byte) 0);
encoder.writeInt(0);
encoder.writeByte((byte) cal.get(Calendar.HOUR_OF_DAY));
encoder.writeByte((byte) cal.get(Calendar.MINUTE));
encoder.writeByte((byte) cal.get(Calendar.SECOND));
}
}
}

Expand Down
41 changes: 22 additions & 19 deletions src/main/java/org/mariadb/jdbc/plugin/codec/TimestampCodec.java
Original file line number Diff line number Diff line change
Expand Up @@ -352,26 +352,29 @@ public void encodeText(
@Override
public void encodeBinary(Writer encoder, Object value, Calendar providedCal, Long maxLength)
throws IOException {
Calendar cal = providedCal == null ? Calendar.getInstance() : providedCal;
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));
encoder.writeByte(cal.get(Calendar.DAY_OF_MONTH));
encoder.writeByte(cal.get(Calendar.HOUR_OF_DAY));
encoder.writeByte(cal.get(Calendar.MINUTE));
encoder.writeByte(cal.get(Calendar.SECOND));
} else {
encoder.writeByte(11); // length
encoder.writeShort((short) cal.get(Calendar.YEAR));
encoder.writeByte((cal.get(Calendar.MONTH) + 1));
encoder.writeByte(cal.get(Calendar.DAY_OF_MONTH));
encoder.writeByte(cal.get(Calendar.HOUR_OF_DAY));
encoder.writeByte(cal.get(Calendar.MINUTE));
encoder.writeByte(cal.get(Calendar.SECOND));
encoder.writeInt(ts.getNanos() / 1000);
Calendar cal = providedCal == null ? Calendar.getInstance() : providedCal;
synchronized (cal) {
cal.clear();
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));
encoder.writeByte(cal.get(Calendar.DAY_OF_MONTH));
encoder.writeByte(cal.get(Calendar.HOUR_OF_DAY));
encoder.writeByte(cal.get(Calendar.MINUTE));
encoder.writeByte(cal.get(Calendar.SECOND));
} else {
encoder.writeByte(11); // length
encoder.writeShort((short) cal.get(Calendar.YEAR));
encoder.writeByte((cal.get(Calendar.MONTH) + 1));
encoder.writeByte(cal.get(Calendar.DAY_OF_MONTH));
encoder.writeByte(cal.get(Calendar.HOUR_OF_DAY));
encoder.writeByte(cal.get(Calendar.MINUTE));
encoder.writeByte(cal.get(Calendar.SECOND));
encoder.writeInt(ts.getNanos() / 1000);
}
}
}

Expand Down
77 changes: 76 additions & 1 deletion src/test/java/org/mariadb/jdbc/integration/BatchTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import static org.junit.jupiter.api.Assertions.*;

import java.sql.*;
import java.util.Calendar;
import java.util.stream.Stream;
import org.junit.jupiter.api.*;
import org.mariadb.jdbc.Connection;
import org.mariadb.jdbc.Statement;
Expand All @@ -20,11 +22,14 @@ public static void beforeAll2() throws SQLException {
stmt.execute(
"CREATE TABLE BatchTest (t1 int not null primary key auto_increment, t2 LONGTEXT)");
createSequenceTables();
stmt.execute("CREATE TABLE timestampCal(id int, val TIMESTAMP)");
}

@AfterAll
public static void after2() throws SQLException {
sharedConn.createStatement().execute("DROP TABLE IF EXISTS BatchTest");
Statement stmt = sharedConn.createStatement();
stmt.execute("DROP TABLE IF EXISTS timestampCal");
stmt.execute("DROP TABLE IF EXISTS BatchTest");
}

@Test
Expand Down Expand Up @@ -414,4 +419,74 @@ private void batchWithError(Connection con) throws SQLException {
assertThrows(BatchUpdateException.class, prep::executeBatch);
}
}

private class TimestampCal {
private Timestamp val;
private int id;

public TimestampCal(Timestamp val, int id) {
this.val = val;
this.id = id;
}

public Timestamp getVal() {
return val;
}

public int getId() {
return id;
}

@Override
public String toString() {
return "TimestampCal{" + "val=" + val + ", id=" + id + '}';
}
}

@Test
public void ensureCalendarSync() throws SQLException {
Assumptions.assumeTrue(isMariaDBServer() && !isXpand());
// to ensure that calendar is use at the same time, using BULK command
TimestampCal[] t1 = new TimestampCal[50];
for (int i = 0; i < 50; i++) {
t1[i] = new TimestampCal(Timestamp.valueOf((1970 + i) + "-01-31 12:00:00.0"), i);
}
TimestampCal[] t2 = new TimestampCal[50];
for (int i = 0; i < 50; i++) {
t2[i] = new TimestampCal(Timestamp.valueOf((1970 + i) + "-12-01 01:12:15.0"), i + 50);
}

Calendar cal = Calendar.getInstance();

int inserts = Stream.of(t1, t2).parallel().mapToInt(l -> insertTimestamp(l, cal)).sum();
assertEquals(100, inserts);
Statement stmt = sharedConn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM timestampCal order by ID");
for (int i = 0; i < 50; i++) {
rs.next();
assertEquals(t1[i].getVal().toString(), rs.getTimestamp(2, cal).toString());
}
for (int i = 0; i < 50; i++) {
rs.next();
assertEquals(t2[i].getVal().toString(), rs.getTimestamp(2, cal).toString());
}
}

private int insertTimestamp(TimestampCal[] vals, Calendar cal) {
try (Connection con = createCon()) {
try (PreparedStatement prep =
con.prepareStatement("INSERT INTO timestampCal(val, id) VALUES (?,?)")) {
for (int i = 0; i < vals.length; i++) {
System.out.println(vals[i]);
prep.setTimestamp(1, vals[i].getVal(), cal);
prep.setInt(2, vals[i].getId());
prep.addBatch();
}
return prep.executeBatch().length;
}
} catch (SQLException e) {
e.printStackTrace();
return -1;
}
}
}

0 comments on commit 22388e6

Please sign in to comment.