From 5a2c940b908936568062f072f0f853a25266d2bb Mon Sep 17 00:00:00 2001 From: Hang Ruan Date: Wed, 15 Mar 2023 15:25:01 +0800 Subject: [PATCH 1/2] Add support for the data type MYSQL_TYPE_TYPED_ARRAY --- .../mysql/binlog/event/deserialization/ColumnType.java | 3 +++ .../deserialization/TableMapEventDataDeserializer.java | 9 ++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/ColumnType.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/ColumnType.java index cc8c9415..1a44490f 100644 --- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/ColumnType.java +++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/ColumnType.java @@ -45,6 +45,9 @@ public enum ColumnType { TIMESTAMP_V2(17), DATETIME_V2(18), TIME_V2(19), + // MYSQL_TYPE_TYPED_ARRAY data type appeared in MySQL 8.0.18+ + // @see https://github.com/mysql/mysql-server/commit/9082b6a820f3948fd563cc32a050f5e8775f2855 + TYPED_ARRAY(20), JSON(245), NEWDECIMAL(246), ENUM(247), diff --git a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/TableMapEventDataDeserializer.java b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/TableMapEventDataDeserializer.java index 6cb814cb..a1d0046d 100644 --- a/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/TableMapEventDataDeserializer.java +++ b/src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/TableMapEventDataDeserializer.java @@ -21,6 +21,8 @@ import java.io.IOException; +import static com.github.shyiko.mysql.binlog.event.deserialization.ColumnType.TYPED_ARRAY; + /** * @author Stanley Shyiko */ @@ -78,7 +80,12 @@ private int numericColumnCount(byte[] types) { private int[] readMetadata(ByteArrayInputStream inputStream, byte[] columnTypes) throws IOException { int[] metadata = new int[columnTypes.length]; for (int i = 0; i < columnTypes.length; i++) { - switch(ColumnType.byCode(columnTypes[i] & 0xFF)) { + ColumnType columnType = ColumnType.byCode(columnTypes[i] & 0xFF); + if (columnType == TYPED_ARRAY) { + byte[] arrayType = inputStream.read(1); + columnType = ColumnType.byCode(arrayType[0] & 0xFF); + } + switch(columnType) { case FLOAT: case DOUBLE: case BLOB: From 0ba131e1835b76fbc579b9fec3610f8a2ed3414e Mon Sep 17 00:00:00 2001 From: Hang Ruan Date: Sun, 26 Mar 2023 23:47:00 +0800 Subject: [PATCH 2/2] Add tests for the data type MYSQL_TYPE_TYPED_ARRAY --- .../TableMapEventDataDeserializerTest.java | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/TableMapEventDataDeserializerTest.java diff --git a/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/TableMapEventDataDeserializerTest.java b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/TableMapEventDataDeserializerTest.java new file mode 100644 index 00000000..7431b68d --- /dev/null +++ b/src/test/java/com/github/shyiko/mysql/binlog/event/deserialization/TableMapEventDataDeserializerTest.java @@ -0,0 +1,128 @@ +/* + * Copyright 2017 Juan Olivares + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.github.shyiko.mysql.binlog.event.deserialization; + +import com.github.shyiko.mysql.binlog.event.TableMapEventData; +import com.github.shyiko.mysql.binlog.event.TableMapEventMetadata; +import com.github.shyiko.mysql.binlog.io.ByteArrayInputStream; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.util.BitSet; + +import static org.testng.Assert.assertEquals; + +/** + * Tests for {@link TableMapEventDataDeserializer}. + */ +public class TableMapEventDataDeserializerTest { + @Test + public void deserialize() throws IOException { + TableMapEventDataDeserializer deserializer = new TableMapEventDataDeserializer(); + // The Table_map_event data. See its format at + // https://dev.mysql.com/doc/dev/mysql-server/latest/classbinary__log_1_1Table__map__event.html + byte[] data = { + // table_id : 6 bytes + 1, + 0, + 0, + 0, + 0, + 0, + // flags : 2 bytes + 1, + 0, + // database_name string length : 1 byte + 6, + // database_name null-terminated string, end with 0 + 116, + 101, + 115, + 116, + 68, + 98, + 0, + // table_name string length : 1 byte + 9, + // table_name null-terminated string, end with 0 + 116, + 101, + 115, + 116, + 84, + 97, + 98, + 108, + 101, + 0, + // column_count + 3, + // column_type list + 8, + 1, + 20, + // metadata_length + 1, + // metadata + 8, + // null_bits + 80, + // optional metadata fields stored in Type, Length, Value(TLV) format. + // Type takes 1 byte. Length is a packed integer value. Values takes Length bytes. + + // SIGNEDNESS + 1, + 1, + 0, + // DEFAULT_CHARSET + 2, + 1, + 45 + }; + TableMapEventData eventData = deserializer.deserialize(new ByteArrayInputStream(data)); + assertEquals(eventData.toString(), getExpectedEventData().toString()); + } + + private TableMapEventData getExpectedEventData() { + TableMapEventData eventData = new TableMapEventData(); + // table_id + eventData.setTableId(1); + // database_name + eventData.setDatabase("testDb"); + // table_name + eventData.setTable("testTable"); + + // column_type + // 3 column types: MYSQL_TYPE_LONGLONG, MYSQL_TYPE_TINY, MYSQL_TYPE_TYPED_ARRAY + eventData.setColumnTypes(new byte[] {8, 1, 20}); + + // metadata of the column types + eventData.setColumnMetadata(new int[] {0, 0, 0}); + + // null_bits + eventData.setColumnNullability(new BitSet()); + + // optional metadata fields + TableMapEventMetadata metadata = new TableMapEventMetadata(); + metadata.setSignedness(new BitSet()); + TableMapEventMetadata.DefaultCharset charset = new TableMapEventMetadata.DefaultCharset(); + charset.setDefaultCharsetCollation(45); + metadata.setDefaultCharset(charset); + eventData.setEventMetadata(metadata); + return eventData; + } +}