This is an automated email from the ASF dual-hosted git repository.
RaigorJiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 190e8ca08f1 Fix microsecond loss in MySQL binary Timestamp output
(#40236)
190e8ca08f1 is described below
commit 190e8ca08f11a05309efb69c14fc17e19da22314
Author: Raigor <[email protected]>
AuthorDate: Tue Oct 20 07:13:24 2026 +0800
Fix microsecond loss in MySQL binary Timestamp output (#40236)
* Fix microsecond loss in MySQL binary Timestamp output
* Refine MySQL binary temporal value conversion
---
.../protocol/MySQLDateBinaryProtocolValue.java | 7 ++-
.../protocol/MySQLDateBinaryProtocolValueTest.java | 51 +++++++++++++---------
2 files changed, 36 insertions(+), 22 deletions(-)
diff --git
a/database/protocol/dialect/mysql/src/main/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLDateBinaryProtocolValue.java
b/database/protocol/dialect/mysql/src/main/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLDateBinaryProtocolValue.java
index 8638cbdfd70..f108380146a 100644
---
a/database/protocol/dialect/mysql/src/main/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLDateBinaryProtocolValue.java
+++
b/database/protocol/dialect/mysql/src/main/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLDateBinaryProtocolValue.java
@@ -19,6 +19,7 @@ package
org.apache.shardingsphere.database.protocol.mysql.packet.command.query.b
import lombok.RequiredArgsConstructor;
import
org.apache.shardingsphere.database.protocol.mysql.payload.MySQLPacketPayload;
+import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
@@ -62,12 +63,16 @@ public final class MySQLDateBinaryProtocolValue implements
MySQLBinaryProtocolVa
}
@Override
+ @HighFrequencyInvocation
public void write(final MySQLPacketPayload payload, final Object value) {
LocalDateTime dateTime;
if (value instanceof LocalDate) {
dateTime = ((LocalDate) value).atStartOfDay();
+ } else if (value instanceof LocalDateTime) {
+ dateTime = (LocalDateTime) value;
} else {
- dateTime = value instanceof LocalDateTime ? (LocalDateTime) value
: new Timestamp(((Date) value).getTime()).toLocalDateTime();
+ Timestamp timestamp = value instanceof Timestamp ? (Timestamp)
value : new Timestamp(((Date) value).getTime());
+ dateTime = timestamp.toLocalDateTime();
}
DateTimeValues values = buildDateTimeValues(dateTime);
boolean isTimeAbsent = 0 == values.hours && 0 == values.minutes && 0
== values.seconds;
diff --git
a/database/protocol/dialect/mysql/src/test/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLDateBinaryProtocolValueTest.java
b/database/protocol/dialect/mysql/src/test/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLDateBinaryProtocolValueTest.java
index 7a001f31765..0db92750698 100644
---
a/database/protocol/dialect/mysql/src/test/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLDateBinaryProtocolValueTest.java
+++
b/database/protocol/dialect/mysql/src/test/java/org/apache/shardingsphere/database/protocol/mysql/packet/command/query/binary/execute/protocol/MySQLDateBinaryProtocolValueTest.java
@@ -17,24 +17,25 @@
package
org.apache.shardingsphere.database.protocol.mysql.packet.command.query.binary.execute.protocol;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
import
org.apache.shardingsphere.database.protocol.mysql.payload.MySQLPacketPayload;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
-import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
+import java.nio.charset.StandardCharsets;
+import java.sql.Date;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
-import java.util.LinkedList;
-import java.util.List;
import java.util.stream.Stream;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -42,7 +43,6 @@ import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -84,23 +84,25 @@ class MySQLDateBinaryProtocolValueTest {
@MethodSource("writeArguments")
void assertWrite(final String name, final Object value, final int
expectedLength, final int year, final int month,
final int dayOfMonth, final int hour, final int minute,
final int second, final Integer expectedMicroseconds) {
- new MySQLDateBinaryProtocolValue().write(payload, value);
- verify(payload).writeInt2(year);
- List<Integer> expectedValues = new LinkedList<>();
- expectedValues.add(expectedLength);
- expectedValues.add(month);
- expectedValues.add(dayOfMonth);
- if (4 != expectedLength) {
- expectedValues.add(hour);
- expectedValues.add(minute);
- expectedValues.add(second);
+ ByteBuf buffer = Unpooled.buffer();
+ try {
+ new MySQLDateBinaryProtocolValue().write(new
MySQLPacketPayload(buffer, StandardCharsets.UTF_8), value);
+ assertThat(buffer.readUnsignedByte(), is((short) expectedLength));
+ assertThat(buffer.readUnsignedShortLE(), is(year));
+ assertThat(buffer.readUnsignedByte(), is((short) month));
+ assertThat(buffer.readUnsignedByte(), is((short) dayOfMonth));
+ if (4 != expectedLength) {
+ assertThat(buffer.readUnsignedByte(), is((short) hour));
+ assertThat(buffer.readUnsignedByte(), is((short) minute));
+ assertThat(buffer.readUnsignedByte(), is((short) second));
+ }
+ if (11 == expectedLength) {
+ assertThat(buffer.readUnsignedIntLE(),
is(expectedMicroseconds.longValue()));
+ }
+ assertThat(buffer.readableBytes(), is(0));
+ } finally {
+ buffer.release();
}
- ArgumentCaptor<Integer> int1Captor =
ArgumentCaptor.forClass(Integer.class);
- verify(payload,
times(expectedValues.size())).writeInt1(int1Captor.capture());
- if (11 == expectedLength) {
- verify(payload).writeInt4(expectedMicroseconds);
- }
- assertThat(int1Captor.getAllValues(), is(expectedValues));
}
@Test
@@ -159,12 +161,19 @@ class MySQLDateBinaryProtocolValueTest {
private static Stream<Arguments> writeArguments() {
return Stream.of(
Arguments.of("local-date", LocalDate.of(1970, 1, 14), 4, 1970,
1, 14, 0, 0, 0, null),
+ Arguments.of("sql-date", Date.valueOf("1970-01-14"), 4, 1970,
1, 14, 0, 0, 0, null),
Arguments.of("local-date-time-date-only",
LocalDateTime.of(1970, 1, 14, 0, 0, 0), 4, 1970, 1, 14, 0, 0, 0, null),
Arguments.of("local-date-time-minute-only",
LocalDateTime.of(1970, 1, 14, 0, 1, 0), 7, 1970, 1, 14, 0, 1, 0, null),
Arguments.of("local-date-time-second-only",
LocalDateTime.of(1970, 1, 14, 0, 0, 1), 7, 1970, 1, 14, 0, 0, 1, null),
Arguments.of("local-date-time-with-time",
LocalDateTime.of(1970, 1, 14, 12, 10, 30), 7, 1970, 1, 14, 12, 10, 30, null),
+ Arguments.of("local-date-time-with-microseconds",
LocalDateTime.of(1970, 1, 14, 12, 10, 30, 123456000), 11, 1970, 1, 14, 12, 10,
30, 123456),
+ Arguments.of("timestamp-date-only",
Timestamp.valueOf("1970-01-14 00:00:00"), 4, 1970, 1, 14, 0, 0, 0, null),
Arguments.of("timestamp-with-time",
Timestamp.valueOf("1970-01-14 12:10:30"), 7, 1970, 1, 14, 12, 10, 30, null),
- Arguments.of("timestamp-with-microseconds",
Timestamp.valueOf("1970-01-14 12:10:30.123"), 11, 1970, 1, 14, 12, 10, 30,
123000),
+ Arguments.of("timestamp-with-milliseconds",
Timestamp.valueOf("1970-01-14 12:10:30.123"), 11, 1970, 1, 14, 12, 10, 30,
123000),
+ Arguments.of("timestamp-with-microseconds",
Timestamp.valueOf("1970-01-14 12:10:30.123456"), 11, 1970, 1, 14, 12, 10, 30,
123456),
+ Arguments.of("timestamp-with-single-microsecond",
Timestamp.valueOf("1970-01-14 12:10:30.000001"), 11, 1970, 1, 14, 12, 10, 30,
1),
+ Arguments.of("timestamp-with-fractional-trailing-zero",
Timestamp.valueOf("1970-01-14 12:10:30.123450"), 11, 1970, 1, 14, 12, 10, 30,
123450),
+ Arguments.of("timestamp-midnight-with-microsecond",
Timestamp.valueOf("1970-01-14 00:00:00.000001"), 11, 1970, 1, 14, 0, 0, 0, 1),
Arguments.of("time-absent-with-nanos", LocalDateTime.of(1970,
1, 14, 0, 0, 0, 1_000), 11, 1970, 1, 14, 0, 0, 0, 1));
}
}