Skip to content

add DATE_AND_TIME_AS_STRING #232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Map;
Expand Down Expand Up @@ -75,6 +76,7 @@ public abstract class AbstractRowsEventDataDeserializer<T extends EventData> imp
private Long invalidDateAndTimeRepresentation;
private boolean microsecondsPrecision;
private boolean deserializeCharAndBinaryAsByteArray;
private boolean deserializeDateAndTimeAsString;

public AbstractRowsEventDataDeserializer(Map<Long, TableMapEventData> tableMapEventByTableId) {
this.tableMapEventByTableId = tableMapEventByTableId;
Expand All @@ -83,6 +85,9 @@ public AbstractRowsEventDataDeserializer(Map<Long, TableMapEventData> tableMapEv
void setDeserializeDateAndTimeAsLong(boolean value) {
this.deserializeDateAndTimeAsLong = value;
}
void setDeserializeDateAndTimeAsString(boolean value) {
this.deserializeDateAndTimeAsString = value;
}

// value to return in case of 0000-00-00 00:00:00, 0000-00-00, etc.
void setInvalidDateAndTimeRepresentation(Long value) {
Expand Down Expand Up @@ -247,6 +252,15 @@ private Long castTimestamp(Long timestamp, int fsp) {

protected Serializable deserializeDate(ByteArrayInputStream inputStream) throws IOException {
int value = inputStream.readInteger(3);
if (deserializeDateAndTimeAsString) {
String result;
if (value == 0) {
result = "0000-00-00";
} else {
result = String.format("%04d-%02d-%02d", value / (16 * 32), value / 32 % 16, value % 32);
}
return result;
}
int day = value % 32;
value >>>= 5;
int month = value % 16;
Expand All @@ -260,6 +274,21 @@ protected Serializable deserializeDate(ByteArrayInputStream inputStream) throws

protected Serializable deserializeTime(ByteArrayInputStream inputStream) throws IOException {
int value = inputStream.readInteger(3);
if (deserializeDateAndTimeAsString) {
String result;
final int i32 = value;
final int u32 = Math.abs(i32);
if (i32 == 0) {
result = "00:00:00";
} else {
result = String.format("%s%02d:%02d:%02d",
(i32 >= 0) ? "" : "-",
u32 / 10000,
(u32 % 10000) / 100,
u32 % 100);
}
return result;
}
int[] split = split(value, 100, 3);
Long timestamp = asUnixTime(1970, 1, 1, split[2], split[1], split[0], 0);
if (deserializeDateAndTimeAsLong) {
Expand All @@ -284,6 +313,28 @@ protected Serializable deserializeTimeV2(int meta, ByteArrayInputStream inputStr
*/
long time = bigEndianLong(inputStream.read(3), 0, 3);
int fsp = deserializeFractionalSeconds(meta, inputStream);
if (deserializeDateAndTimeAsString) {
String result;
int sign = bitSlice(time, 0, 1, 24);
if (sign == 0) {
time = time & 0xffffffL;
time = time - 0x800000L;
}
if (time == 0) {
result = "00:00:00";
} else {
long ultime = Math.abs(time);
result = String.format("%s%02d:%02d:%02d",
sign != 0 ? "" : "-",
(int) bitSlice(ultime, 2, 10, 24),
(int) bitSlice(ultime, 12, 6, 24),
(int) bitSlice(ultime, 18, 6, 24));
}
if (fsp > 0) {
result = String.format("%s.%6d", result, fsp);
}
return result;
}
Long timestamp = asUnixTime(1970, 1, 1,
bitSlice(time, 2, 10, 24),
bitSlice(time, 12, 6, 24),
Expand All @@ -298,6 +349,16 @@ protected Serializable deserializeTimeV2(int meta, ByteArrayInputStream inputStr

protected Serializable deserializeTimestamp(ByteArrayInputStream inputStream) throws IOException {
long timestamp = inputStream.readLong(4) * 1000;
if (deserializeDateAndTimeAsString) {
String result;
if (timestamp == 0) {
result = "0000-00-00 00:00:00";
} else {
String v = new Timestamp(timestamp).toString();
result = v.substring(0, v.length() - 2);
}
return result;
}
if (deserializeDateAndTimeAsLong) {
return castTimestamp(timestamp, 0);
}
Expand All @@ -307,6 +368,26 @@ protected Serializable deserializeTimestamp(ByteArrayInputStream inputStream) th
protected Serializable deserializeTimestampV2(int meta, ByteArrayInputStream inputStream) throws IOException {
long millis = bigEndianLong(inputStream.read(4), 0, 4);
int fsp = deserializeFractionalSeconds(meta, inputStream);
if (deserializeDateAndTimeAsString) {
String result;
String second;
if (millis == 0) {
second = "0000-00-00 00:00:00";
} else {
Timestamp time = new Timestamp(millis * 1000);
second = time.toString();
// 去掉毫秒精度.0
second = second.substring(0, second.length() - 2);
}
if (meta >= 1) {
String microSecond = usecondsToStr(fsp, meta);
microSecond = microSecond.substring(0, meta);
result = second + '.' + microSecond;
} else {
result = second;
}
return result;
}
long timestamp = millis * 1000 + fsp / 1000;
if (deserializeDateAndTimeAsLong) {
return castTimestamp(timestamp, fsp);
Expand All @@ -315,8 +396,26 @@ protected Serializable deserializeTimestampV2(int meta, ByteArrayInputStream inp
}

protected Serializable deserializeDatetime(ByteArrayInputStream inputStream) throws IOException {
int[] split = split(inputStream.readLong(8), 100, 6);
Long i64 = inputStream.readLong(8);
int[] split = split(i64, 100, 6);
Long timestamp = asUnixTime(split[5], split[4], split[3], split[2], split[1], split[0], 0);
if (deserializeDateAndTimeAsString) {
String result;
if (i64 == 0) {
result = "0000-00-00 00:00:00";
} else {
final int d = (int) (i64 / 1000000);
final int t = (int) (i64 % 1000000);
result = String.format("%04d-%02d-%02d %02d:%02d:%02d",
d / 10000,
(d % 10000) / 100,
d % 100,
t / 10000,
(t % 10000) / 100,
t % 100);
}
return result;
}
if (deserializeDateAndTimeAsLong) {
return castTimestamp(timestamp, 0);
}
Expand All @@ -339,8 +438,43 @@ protected Serializable deserializeDatetimeV2(int meta, ByteArrayInputStream inpu
+ fractional-seconds storage (size depends on meta)
*/
long datetime = bigEndianLong(inputStream.read(5), 0, 5);
int yearMonth = bitSlice(datetime, 1, 17, 40);
int fsp = deserializeFractionalSeconds(meta, inputStream);
if (deserializeDateAndTimeAsString) {
String result;
int sign = bitSlice(datetime, 0, 0, 40);
if (sign == 0) {
datetime = datetime & 0xffffffffffL;
datetime = datetime - 0x8000000000L;
}
long intpart = datetime;
int frac = fsp;

String second = null;
if (intpart == 0) {
second = "0000-00-00 00:00:00";
} else {
long ymd = intpart >> 17;
long ym = ymd >> 5;
long hms = intpart % (1 << 17);
second = String.format("%04d-%02d-%02d %02d:%02d:%02d",
(int) (ym / 13),
(int) (ym % 13),
(int) (ymd % (1 << 5)),
(int) (hms >> 12),
(int) ((hms >> 6) % (1 << 6)),
(int) (hms % (1 << 6)));
}
if (meta >= 1) {
String microSecond = usecondsToStr(frac, meta);
microSecond = microSecond.substring(0, meta);
result = second + '.' + microSecond;
} else {
result = second;
}

return result;
}
int yearMonth = bitSlice(datetime, 1, 17, 40);
Long timestamp = asUnixTime(
yearMonth / 13,
yearMonth % 13,
Expand All @@ -357,7 +491,17 @@ protected Serializable deserializeDatetimeV2(int meta, ByteArrayInputStream inpu
}

protected Serializable deserializeYear(ByteArrayInputStream inputStream) throws IOException {
return 1900 + inputStream.readInteger(1);
int year = inputStream.readInteger(1);
if (deserializeDateAndTimeAsString) {
String result;
if (year == 0) {
result = "0000";
} else {
result = String.valueOf((short) (year + 1900));
}
return result;
}
return 1900 + year;
}

protected Serializable deserializeString(int length, ByteArrayInputStream inputStream) throws IOException {
Expand Down Expand Up @@ -452,6 +596,23 @@ private static int[] split(long value, int divider, int length) {
return result;
}

private String usecondsToStr(int frac, int meta) {
String sec = String.valueOf(frac);
if (meta > 6) {
throw new IllegalArgumentException("unknow useconds meta : " + meta);
}
if (sec.length() < 6) {
StringBuilder result = new StringBuilder(6);
int len = 6 - sec.length();
for (; len > 0; len--) {
result.append('0');
}
result.append(sec);
sec = result.toString();
}
return sec.substring(0, meta);
}

/**
* see mysql/strings/decimal.c
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,9 @@ private void ensureCompatibility(EventDataDeserializer eventDataDeserializer) {
deserializer.setDeserializeCharAndBinaryAsByteArray(
compatibilitySet.contains(CompatibilityMode.CHAR_AND_BINARY_AS_BYTE_ARRAY)
);
deserializer.setDeserializeDateAndTimeAsString(
compatibilitySet.contains(CompatibilityMode.DATE_AND_TIME_AS_STRING)
);
}
}

Expand Down Expand Up @@ -288,7 +291,11 @@ public enum CompatibilityMode {
*
* <p>This option is going to be enabled by default starting from mysql-binlog-connector-java@1.0.0.
*/
CHAR_AND_BINARY_AS_BYTE_ARRAY
CHAR_AND_BINARY_AS_BYTE_ARRAY,
/**
* Return DATETIME/DATETIME_V2/TIMESTAMP/TIMESTAMP_V2/DATE/TIME/TIME_V2 values as String
*/
DATE_AND_TIME_AS_STRING
}

/**
Expand Down