2626import java .util .LinkedHashMap ;
2727import java .util .List ;
2828import java .util .Map ;
29+ import java .util .logging .Level ;
30+ import java .util .logging .Logger ;
2931
3032/**
3133 * @author <a href="mailto:ahmedahamid@yahoo.com">Ahmed Abdul Hamid</a>
3234 */
3335public 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