Skip to content

Commit 2cbc106

Browse files
authored
Merge pull request #11 from fivetran/handle-unknown-metadata-field-type
feature(table_map_event_data_serializer): add support of ColumnVisibility metadata and handle unknown metadata field type
2 parents ded5e80 + f391a50 commit 2cbc106

File tree

3 files changed

+42
-6
lines changed

3 files changed

+42
-6
lines changed

src/main/java/com/github/shyiko/mysql/binlog/event/TableMapEventMetadata.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class TableMapEventMetadata implements EventData {
3636
private Map<Integer, Integer> primaryKeysWithPrefix;
3737
private DefaultCharset enumAndSetDefaultCharset;
3838
private List<Integer> enumAndSetColumnCharsets;
39+
private BitSet visibility;
3940

4041
public BitSet getSignedness() {
4142
return signedness;
@@ -125,6 +126,14 @@ public void setEnumAndSetColumnCharsets(List<Integer> enumAndSetColumnCharsets)
125126
this.enumAndSetColumnCharsets = enumAndSetColumnCharsets;
126127
}
127128

129+
public BitSet getVisibility() {
130+
return visibility;
131+
}
132+
133+
public void setVisibility(BitSet visibility) {
134+
this.visibility = visibility;
135+
}
136+
128137
@Override
129138
public String toString() {
130139
final StringBuilder sb = new StringBuilder();
@@ -163,6 +172,8 @@ public String toString() {
163172
sb.append(", enumAndSetColumnCharsets=").append(enumAndSetColumnCharsets == null ? "null" : "");
164173
appendList(sb, enumAndSetColumnCharsets);
165174

175+
sb.append(",visibility=").append(visibility);
176+
166177
sb.append('}');
167178
return sb.toString();
168179
}

src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/TableMapEventDataDeserializer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public TableMapEventData deserialize(ByteArrayInputStream inputStream) throws IO
4646
if (metadataLength > 0) {
4747
metadata = metadataDeserializer.deserialize(
4848
new ByteArrayInputStream(inputStream.read(metadataLength)),
49+
eventData.getColumnTypes().length,
4950
numericColumnCount(eventData.getColumnTypes())
5051
);
5152
}

src/main/java/com/github/shyiko/mysql/binlog/event/deserialization/TableMapEventMetadataDeserializer.java

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,17 @@
2626
import java.util.LinkedHashMap;
2727
import java.util.List;
2828
import java.util.Map;
29+
import java.util.logging.Level;
30+
import java.util.logging.Logger;
2931

3032
/**
3133
* @author <a href="mailto:[email protected]">Ahmed Abdul Hamid</a>
3234
*/
3335
public class TableMapEventMetadataDeserializer {
3436

35-
public TableMapEventMetadata deserialize(ByteArrayInputStream inputStream, int nIntColumns) throws IOException {
37+
private final Logger logger = Logger.getLogger(getClass().getName());
38+
39+
public TableMapEventMetadata deserialize(ByteArrayInputStream inputStream, int nColumns, int nNumericColumns) throws IOException {
3640
int remainingBytes = inputStream.available();
3741
if (remainingBytes <= 0) {
3842
return null;
@@ -41,15 +45,27 @@ public TableMapEventMetadata deserialize(ByteArrayInputStream inputStream, int n
4145
TableMapEventMetadata result = new TableMapEventMetadata();
4246

4347
for (; remainingBytes > 0; inputStream.enterBlock(remainingBytes)) {
44-
MetadataFieldType fieldType = MetadataFieldType.byCode(inputStream.readInteger(1));
48+
int code = inputStream.readInteger(1);
49+
50+
MetadataFieldType fieldType = MetadataFieldType.byCode(code);
51+
52+
if(fieldType == null)
53+
throw new IOException("Unsupported table metadata field type " + code);
54+
55+
//for some reasons, the UNKNOWN_METADATA_FIELD_TYPE will mess up the stream
56+
if(inputStream.available() == 0) {
57+
logger.warning("Stream is empty so cannot read field length for field type: " + fieldType);
58+
return result;
59+
}
60+
4561
int fieldLength = inputStream.readPackedInteger();
4662

4763
remainingBytes = inputStream.available();
4864
inputStream.enterBlock(fieldLength);
4965

5066
switch (fieldType) {
5167
case SIGNEDNESS:
52-
result.setSignedness(readSignedness(inputStream, nIntColumns));
68+
result.setSignedness(readBooleanList(inputStream, nNumericColumns));
5369
break;
5470
case DEFAULT_CHARSET:
5571
result.setDefaultCharset(readDefaultCharset(inputStream));
@@ -81,16 +97,22 @@ public TableMapEventMetadata deserialize(ByteArrayInputStream inputStream, int n
8197
case ENUM_AND_SET_COLUMN_CHARSET:
8298
result.setEnumAndSetColumnCharsets(readIntegers(inputStream));
8399
break;
100+
case VISIBILITY:
101+
result.setVisibility(readBooleanList(inputStream, nColumns));
102+
break;
103+
case UNKNOWN_METADATA_FIELD_TYPE:
104+
logger.warning("Received metadata field of unknown type");
105+
break;
84106
default:
85107
inputStream.enterBlock(remainingBytes);
86-
throw new IOException("Unsupported table metadata field type " + fieldType);
108+
throw new IOException("Unsupported table metadata field type " + code);
87109
}
88110
remainingBytes -= fieldLength;
89111
}
90112
return result;
91113
}
92114

93-
private static BitSet readSignedness(ByteArrayInputStream inputStream, int length) throws IOException {
115+
private static BitSet readBooleanList(ByteArrayInputStream inputStream, int length) throws IOException {
94116
BitSet result = new BitSet();
95117
// according to MySQL internals the amount of storage required for N columns is INT((N+7)/8) bytes
96118
byte[] bytes = inputStream.read((length + 7) >> 3);
@@ -162,7 +184,9 @@ private enum MetadataFieldType {
162184
SIMPLE_PRIMARY_KEY(8), // The primary key without any prefix
163185
PRIMARY_KEY_WITH_PREFIX(9), // The primary key with some prefix
164186
ENUM_AND_SET_DEFAULT_CHARSET(10), // Charsets of ENUM and SET columns
165-
ENUM_AND_SET_COLUMN_CHARSET(11); // Charsets of ENUM and SET columns
187+
ENUM_AND_SET_COLUMN_CHARSET(11), // Charsets of ENUM and SET columns
188+
VISIBILITY(12), // Column visibility (8.0.23 and newer)
189+
UNKNOWN_METADATA_FIELD_TYPE(128); // Returned from MySQL 8.0 in some cases
166190

167191
private final int code;
168192

0 commit comments

Comments
 (0)