From fffcad48649ee6e602c2955153050329949a3b2c Mon Sep 17 00:00:00 2001 From: BillyYccc Date: Sat, 22 Jul 2023 15:41:46 +0800 Subject: [PATCH] MySQL client data type mapping rework - fixes #1239 --- .../mysqlclient/impl/codec/CommandCodec.java | 6 +- .../codec/ExtendedQueryCommandBaseCodec.java | 2 +- .../impl/codec/RowResultDecoder.java | 6 +- .../mysqlclient/impl/datatype/DataType.java | 172 ++++++++++---- .../impl/datatype/DataTypeCodec.java | 223 +++++++++--------- .../impl/protocol/ColumnDefinition.java | 56 ++--- .../data/SpatialDataTypeCodecTestBase.java | 15 ++ .../tck/MySQLBinaryDataTypeDecodeTest.java | 79 ++++++- .../tck/MySQLTextDataTypeDecodeTest.java | 63 +++++ 9 files changed, 427 insertions(+), 195 deletions(-) diff --git a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/CommandCodec.java b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/CommandCodec.java index 570fdd8f0..3c64a73c2 100644 --- a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/CommandCodec.java +++ b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/CommandCodec.java @@ -176,7 +176,7 @@ ColumnDefinition decodeColumnDefinitionPacketPayload(ByteBuf payload) { int characterSet = payload.getUnsignedShortLE(start + bytesToSkip); bytesToSkip += 6; // characterSet + columnLength - DataType type = DataType.valueOf(payload.getUnsignedByte(start + bytesToSkip)); + short type = payload.getUnsignedByte(start + bytesToSkip); bytesToSkip++; int flags = payload.getUnsignedShortLE(start + bytesToSkip); @@ -184,7 +184,9 @@ ColumnDefinition decodeColumnDefinitionPacketPayload(ByteBuf payload) { payload.skipBytes(bytesToSkip); - return new ColumnDefinition(name, characterSet, type, flags); + // convert type+characterset+flags to dataType + DataType dataType = DataType.parseDataType(type, characterSet, flags); + return new ColumnDefinition(name, characterSet, dataType, flags); } void skipEofPacketIfNeeded(ByteBuf payload) { diff --git a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/ExtendedQueryCommandBaseCodec.java b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/ExtendedQueryCommandBaseCodec.java index e0e35c048..ff4bf3b6d 100644 --- a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/ExtendedQueryCommandBaseCodec.java +++ b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/ExtendedQueryCommandBaseCodec.java @@ -98,7 +98,7 @@ protected final void sendStatementExecuteCommand(MySQLPreparedStatement statemen if (sendTypesToServer) { for (DataType bindingType : statement.bindingTypes()) { - packet.writeByte(bindingType.id); + packet.writeByte(bindingType.getColumnType()); packet.writeByte(0); // parameter flag: signed } } diff --git a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/RowResultDecoder.java b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/RowResultDecoder.java index 3c95c5b77..d3ad9a92a 100644 --- a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/RowResultDecoder.java +++ b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/RowResultDecoder.java @@ -57,8 +57,7 @@ protected Row decodeRow(int len, ByteBuf in) { ColumnDefinition columnDef = rowDesc.get(c); DataType dataType = columnDef.type(); int collationId = columnDef.characterSet(); - int columnDefinitionFlags = columnDef.flags(); - decoded = DataTypeCodec.decodeBinary(dataType, collationId, columnDefinitionFlags, in); + decoded = DataTypeCodec.decodeBinary(dataType, collationId, in); } row.addValue(decoded); } @@ -71,9 +70,8 @@ protected Row decodeRow(int len, ByteBuf in) { } else { ColumnDefinition columnDef = rowDesc.get(c); DataType dataType = columnDef.type(); - int columnDefinitionFlags = columnDef.flags(); int collationId = columnDef.characterSet(); - decoded = DataTypeCodec.decodeText(dataType, collationId, columnDefinitionFlags, in); + decoded = DataTypeCodec.decodeText(dataType, collationId, in); } row.addValue(decoded); } diff --git a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/datatype/DataType.java b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/datatype/DataType.java index f9a3d5c92..853e707a9 100644 --- a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/datatype/DataType.java +++ b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/datatype/DataType.java @@ -11,75 +11,161 @@ package io.vertx.mysqlclient.impl.datatype; -import io.netty.util.collection.IntObjectHashMap; -import io.netty.util.collection.IntObjectMap; +import io.netty.util.collection.ShortObjectHashMap; +import io.netty.util.collection.ShortObjectMap; import io.vertx.core.buffer.Buffer; import io.vertx.core.impl.logging.Logger; import io.vertx.core.impl.logging.LoggerFactory; import io.vertx.mysqlclient.data.spatial.Geometry; +import io.vertx.mysqlclient.impl.MySQLCollation; import io.vertx.mysqlclient.impl.protocol.ColumnDefinition; import io.vertx.sqlclient.data.Numeric; +import java.math.BigInteger; import java.sql.JDBCType; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; public enum DataType { - INT1(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY, Byte.class, Byte.class, JDBCType.TINYINT), - INT2(ColumnDefinition.ColumnType.MYSQL_TYPE_SHORT, Short.class, Short.class, JDBCType.SMALLINT), - INT3(ColumnDefinition.ColumnType.MYSQL_TYPE_INT24, Integer.class, Integer.class, JDBCType.INTEGER), - INT4(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG, Integer.class, Integer.class, JDBCType.INTEGER), - INT8(ColumnDefinition.ColumnType.MYSQL_TYPE_LONGLONG, Long.class, Long.class, JDBCType.BIGINT), - DOUBLE(ColumnDefinition.ColumnType.MYSQL_TYPE_DOUBLE, Double.class, Double.class, JDBCType.DOUBLE), - FLOAT(ColumnDefinition.ColumnType.MYSQL_TYPE_FLOAT, Float.class, Float.class, JDBCType.REAL), - NUMERIC(ColumnDefinition.ColumnType.MYSQL_TYPE_NEWDECIMAL, Numeric.class, Numeric.class, JDBCType.DECIMAL), // DECIMAL - STRING(ColumnDefinition.ColumnType.MYSQL_TYPE_STRING, Buffer.class, String.class, JDBCType.VARCHAR), // CHAR, BINARY - VARSTRING(ColumnDefinition.ColumnType.MYSQL_TYPE_VAR_STRING, Buffer.class, String.class, JDBCType.VARCHAR), //VARCHAR, VARBINARY - TINYBLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY_BLOB, Buffer.class, String.class, JDBCType.BLOB), - BLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_BLOB, Buffer.class, String.class, JDBCType.BLOB), - MEDIUMBLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_MEDIUM_BLOB, Buffer.class, String.class, JDBCType.BLOB), - LONGBLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG_BLOB, Buffer.class, String.class, JDBCType.BLOB), - DATE(ColumnDefinition.ColumnType.MYSQL_TYPE_DATE, LocalDate.class, LocalDate.class, JDBCType.DATE), - TIME(ColumnDefinition.ColumnType.MYSQL_TYPE_TIME, Duration.class, Duration.class, JDBCType.TIME), - DATETIME(ColumnDefinition.ColumnType.MYSQL_TYPE_DATETIME, LocalDateTime.class, LocalDateTime.class, JDBCType.TIMESTAMP), - YEAR(ColumnDefinition.ColumnType.MYSQL_TYPE_YEAR, Short.class, Short.class, JDBCType.SMALLINT), - TIMESTAMP(ColumnDefinition.ColumnType.MYSQL_TYPE_TIMESTAMP, LocalDateTime.class, LocalDateTime.class, JDBCType.TIMESTAMP), - BIT(ColumnDefinition.ColumnType.MYSQL_TYPE_BIT, Long.class, Long.class, JDBCType.BIT), - JSON(ColumnDefinition.ColumnType.MYSQL_TYPE_JSON, Object.class, Object.class, JDBCType.OTHER), - GEOMETRY(ColumnDefinition.ColumnType.MYSQL_TYPE_GEOMETRY, Geometry.class, Geometry.class, JDBCType.OTHER), - NULL(ColumnDefinition.ColumnType.MYSQL_TYPE_NULL, Object.class, Object.class, JDBCType.OTHER), // useful for mariadb prepare statement response - UNBIND(-1, Object.class, Object.class, JDBCType.OTHER); // useful for binding param values + + // unsigned int + U_INT8(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY, Short.class, JDBCType.SMALLINT), + U_INT16(ColumnDefinition.ColumnType.MYSQL_TYPE_SHORT, Integer.class, JDBCType.INTEGER), + U_INT24(ColumnDefinition.ColumnType.MYSQL_TYPE_INT24, Integer.class, JDBCType.INTEGER), + U_INT32(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG, Long.class, JDBCType.BIGINT), + U_INT64(ColumnDefinition.ColumnType.MYSQL_TYPE_LONGLONG, BigInteger.class, JDBCType.NUMERIC), + // signed int + INT8(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY, Byte.class, JDBCType.TINYINT), + INT16(ColumnDefinition.ColumnType.MYSQL_TYPE_SHORT, Short.class, JDBCType.SMALLINT), + INT24(ColumnDefinition.ColumnType.MYSQL_TYPE_INT24, Integer.class, JDBCType.INTEGER), + INT32(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG, Integer.class, JDBCType.INTEGER), + INT64(ColumnDefinition.ColumnType.MYSQL_TYPE_LONGLONG, Long.class, JDBCType.BIGINT), + // numeric + BIT(ColumnDefinition.ColumnType.MYSQL_TYPE_BIT, Long.class, JDBCType.BIT), + DOUBLE(ColumnDefinition.ColumnType.MYSQL_TYPE_DOUBLE, Double.class, JDBCType.DOUBLE), + FLOAT(ColumnDefinition.ColumnType.MYSQL_TYPE_FLOAT, Float.class, JDBCType.FLOAT), + NUMERIC(ColumnDefinition.ColumnType.MYSQL_TYPE_NEWDECIMAL, Numeric.class, JDBCType.DECIMAL), + // string + STRING(ColumnDefinition.ColumnType.MYSQL_TYPE_STRING, String.class, JDBCType.CHAR), + VARSTRING(ColumnDefinition.ColumnType.MYSQL_TYPE_VAR_STRING, String.class, JDBCType.VARCHAR), + // clob + TINY_TEXT(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY_BLOB, String.class, JDBCType.CLOB), + TEXT(ColumnDefinition.ColumnType.MYSQL_TYPE_BLOB, String.class, JDBCType.CLOB), + MEDIUM_TEXT(ColumnDefinition.ColumnType.MYSQL_TYPE_MEDIUM_BLOB, String.class, JDBCType.CLOB), + LONG_TEXT(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG_BLOB, String.class, JDBCType.CLOB), + // binary + BINARY(ColumnDefinition.ColumnType.MYSQL_TYPE_STRING, Buffer.class, JDBCType.BINARY), + VARBINARY(ColumnDefinition.ColumnType.MYSQL_TYPE_VAR_STRING, Buffer.class, JDBCType.VARBINARY), + // blob + TINY_BLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY_BLOB, Buffer.class, JDBCType.BLOB), + BLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_BLOB, Buffer.class, JDBCType.BLOB), + MEDIUM_BLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_MEDIUM_BLOB, Buffer.class, JDBCType.BLOB), + LONG_BLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG_BLOB, Buffer.class, JDBCType.BLOB), + // time + DATE(ColumnDefinition.ColumnType.MYSQL_TYPE_DATE, LocalDate.class, JDBCType.DATE), + TIME(ColumnDefinition.ColumnType.MYSQL_TYPE_TIME, Duration.class, JDBCType.TIME), + DATETIME(ColumnDefinition.ColumnType.MYSQL_TYPE_DATETIME, LocalDateTime.class, JDBCType.TIMESTAMP), + YEAR(ColumnDefinition.ColumnType.MYSQL_TYPE_YEAR, Short.class, JDBCType.SMALLINT), + TIMESTAMP(ColumnDefinition.ColumnType.MYSQL_TYPE_TIMESTAMP, LocalDateTime.class, JDBCType.TIMESTAMP), + + JSON(ColumnDefinition.ColumnType.MYSQL_TYPE_JSON, Object.class, JDBCType.OTHER), + GEOMETRY(ColumnDefinition.ColumnType.MYSQL_TYPE_GEOMETRY, Geometry.class, JDBCType.OTHER), + NULL(ColumnDefinition.ColumnType.MYSQL_TYPE_NULL, Object.class, JDBCType.OTHER), // useful for mariadb prepare statement response + UNBIND((short) -1, Object.class, JDBCType.OTHER); // useful for binding param values + ; private static final Logger LOGGER = LoggerFactory.getLogger(DataType.class); - private static IntObjectMap idToDataType = new IntObjectHashMap<>(); + // protocol id + private final short columnType; - static { - for (DataType dataType : values()) { - idToDataType.put(dataType.id, dataType); - } - } + private final Class javaType; - public final int id; - public final Class binaryType; - public final Class textType; - public final JDBCType jdbcType; + private final JDBCType jdbcType; - DataType(int id, Class binaryType, Class textType, JDBCType jdbcType) { - this.id = id; - this.binaryType = binaryType; - this.textType = textType; + DataType(short columnType, Class javaType, JDBCType jdbcType) { + this.columnType = columnType; + this.javaType = javaType; this.jdbcType = jdbcType; } - public static DataType valueOf(int value) { - DataType dataType = idToDataType.get(value); + public int getColumnType() { + return columnType; + } + + public Class getJavaType() { + return javaType; + } + + public JDBCType getJdbcType() { + return jdbcType; + } + + public static DataType parseDataType(short type, int characterSet, int flags) { + // integer + if (COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.containsKey(type)) { + return isUnsignedNumeric(flags) ? COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.get(type).get(0) : COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.get(type).get(1); + } + + // string + if (COLUMN_TYPE_TO_STRING_TYPE_MAPPING.containsKey(type)) { + return isText(characterSet) ? COLUMN_TYPE_TO_STRING_TYPE_MAPPING.get(type).get(0) : COLUMN_TYPE_TO_STRING_TYPE_MAPPING.get(type).get(1); + } + + // others + DataType dataType = COLUMN_TYPE_TO_DATA_TYPE_MAPPING.get(type); if (dataType == null) { - LOGGER.warn(String.format("MySQL data type Id =[%d] not handled - using string type instead", value)); + LOGGER.warn(String.format("MySQL data type Id =[%d] not handled - using string type instead", type)); return STRING; } else { return dataType; } } + + private static final ShortObjectMap> COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING; + private static final ShortObjectMap> COLUMN_TYPE_TO_STRING_TYPE_MAPPING; + private static final ShortObjectMap COLUMN_TYPE_TO_DATA_TYPE_MAPPING; + + static { + // integer + // column type -> uint, int + COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING = new ShortObjectHashMap<>(5, 1.0f); + COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY, Arrays.asList(U_INT8, INT8)); + COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_SHORT, Arrays.asList(U_INT16, INT16)); + COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_INT24, Arrays.asList(U_INT24, INT24)); + COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG, Arrays.asList(U_INT32, INT32)); + COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_LONGLONG, Arrays.asList(U_INT64, INT64)); + + // string + // column type -> clob, blob + COLUMN_TYPE_TO_STRING_TYPE_MAPPING = new ShortObjectHashMap<>(6, 1.0f); + COLUMN_TYPE_TO_STRING_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_STRING, Arrays.asList(STRING, BINARY)); + COLUMN_TYPE_TO_STRING_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_VAR_STRING, Arrays.asList(VARSTRING, VARBINARY)); + COLUMN_TYPE_TO_STRING_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY_BLOB, Arrays.asList(TINY_TEXT, TINY_BLOB)); + COLUMN_TYPE_TO_STRING_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_BLOB, Arrays.asList(TEXT, BLOB)); + COLUMN_TYPE_TO_STRING_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_MEDIUM_BLOB, Arrays.asList(MEDIUM_TEXT, MEDIUM_BLOB)); + COLUMN_TYPE_TO_STRING_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG_BLOB, Arrays.asList(LONG_TEXT, LONG_BLOB)); + + // others + COLUMN_TYPE_TO_DATA_TYPE_MAPPING = new ShortObjectHashMap<>(13, 1.0f); + for (DataType dataType : DataType.values()) { + if (COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.containsKey(dataType.columnType) || COLUMN_TYPE_TO_STRING_TYPE_MAPPING.containsKey(dataType.columnType)) { + continue; + } + + COLUMN_TYPE_TO_DATA_TYPE_MAPPING.put(dataType.columnType, dataType); + } + } + + private static boolean isText(int collationId) { + return collationId != MySQLCollation.binary.collationId(); + } + + private static boolean isUnsignedNumeric(int columnDefinitionFlags) { + return (columnDefinitionFlags & ColumnDefinition.ColumnDefinitionFlags.UNSIGNED_FLAG) != 0; + } + } diff --git a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/datatype/DataTypeCodec.java b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/datatype/DataTypeCodec.java index fc6ec0e62..a2226cc6a 100644 --- a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/datatype/DataTypeCodec.java +++ b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/datatype/DataTypeCodec.java @@ -19,7 +19,6 @@ import io.vertx.core.json.JsonObject; import io.vertx.mysqlclient.data.spatial.*; import io.vertx.mysqlclient.impl.MySQLCollation; -import io.vertx.mysqlclient.impl.protocol.ColumnDefinition; import io.vertx.mysqlclient.impl.util.BufferUtils; import io.vertx.core.buffer.Buffer; import io.vertx.sqlclient.Tuple; @@ -58,47 +57,35 @@ public class DataTypeCodec { .appendFraction(MICRO_OF_SECOND, 0, 6, true) .toFormatter(); - public static Object decodeText(DataType dataType, int collationId, int columnDefinitionFlags, ByteBuf buffer) { + public static Object decodeText(DataType dataType, int collationId, ByteBuf buffer) { int length = (int) BufferUtils.readLengthEncodedInteger(buffer); int index = buffer.readerIndex(); try { switch (dataType) { - case INT1: - if (isUnsignedNumeric(columnDefinitionFlags)) { - return textDecodeInt2(buffer, index, length); - } else { - return textDecodeInt1(buffer, index, length); - } - case YEAR: - return textDecodeInt2(buffer, index, length); - case INT2: - if (isUnsignedNumeric(columnDefinitionFlags)) { - return textDecodeInt4(buffer, index, length); - } else { - return textDecodeInt2(buffer, index, length); - } - case INT3: - return textDecodeInt4(buffer, index, length); - case INT4: - if (isUnsignedNumeric(columnDefinitionFlags)) { - return textDecodeInt8(buffer, index, length); - } else { - return textDecodeInt4(buffer, index, length); - } case INT8: - if (isUnsignedNumeric(columnDefinitionFlags)) { - return textDecodeNUMERIC(collationId, buffer, index, length); - } else { - return textDecodeInt8(buffer, index, length); - } + return textDecodeInt8(buffer, index, length); + case U_INT8: + case YEAR: + case INT16: + return textDecodeInt16(buffer, index, length); + case INT24: + return textDecodeInt24(buffer, index, length); + case U_INT16: + case U_INT24: + case INT32: + return textDecodeInt32(buffer, index, length); + case U_INT32: + case INT64: + return textDecodeInt64(buffer, index, length); + case U_INT64: + case NUMERIC: + return textDecodeNUMERIC(collationId, buffer, index, length); case FLOAT: return textDecodeFloat(collationId, buffer, index, length); case DOUBLE: return textDecodeDouble(collationId, buffer, index, length); case BIT: return textDecodeBit(buffer, index, length); - case NUMERIC: - return textDecodeNUMERIC(collationId, buffer, index, length); case DATE: return textDecodeDate(collationId, buffer, index, length); case TIME: @@ -110,11 +97,22 @@ public static Object decodeText(DataType dataType, int collationId, int columnDe return textDecodeJson(collationId, buffer, index, length); case GEOMETRY: return textDecodeGeometry(buffer, index, length); + case BINARY: + case VARBINARY: + case TINY_BLOB: + case BLOB: + case MEDIUM_BLOB: + case LONG_BLOB: + return textDecodeBlob(buffer, index, length); case STRING: case VARSTRING: - case BLOB: + case TINY_TEXT: + case TEXT: + case MEDIUM_TEXT: + case LONG_TEXT: + return textDecodeText(collationId, buffer, index, length); default: - return textDecodeBlobOrText(collationId, columnDefinitionFlags, buffer, index, length); + return textDecodeBlobOrText(collationId, buffer, index, length); } } finally { buffer.readerIndex(index + length); @@ -123,7 +121,7 @@ public static Object decodeText(DataType dataType, int collationId, int columnDe public static void encodeBinary(DataType dataType, Object value, Charset charset, ByteBuf buffer) { switch (dataType) { - case INT1: + case INT8: if (value instanceof Boolean) { if ((Boolean) value) { value = 1; @@ -131,19 +129,19 @@ public static void encodeBinary(DataType dataType, Object value, Charset charset value = 0; } } - binaryEncodeInt1((Number) value, buffer); + binaryEncodeInt8((Number) value, buffer); break; - case INT2: - binaryEncodeInt2((Number) value, buffer); + case INT16: + binaryEncodeInt16((Number) value, buffer); break; - case INT3: - binaryEncodeInt3((Number) value, buffer); + case INT24: + binaryEncodeInt24((Number) value, buffer); break; - case INT4: - binaryEncodeInt4((Number) value, buffer); + case INT32: + binaryEncodeInt32((Number) value, buffer); break; - case INT8: - binaryEncodeInt8((Number) value, buffer); + case INT64: + binaryEncodeInt64((Number) value, buffer); break; case FLOAT: binaryEncodeFloat((Number) value, buffer); @@ -193,40 +191,29 @@ public static void encodeBinary(DataType dataType, Object value, Charset charset } } - public static Object decodeBinary(DataType dataType, int collationId, int columnDefinitionFlags, ByteBuf buffer) { + public static Object decodeBinary(DataType dataType, int collationId, ByteBuf buffer) { switch (dataType) { - case INT1: - if (isUnsignedNumeric(columnDefinitionFlags)) { - return binaryDecodeUnsignedInt1(buffer); - } else { - return binaryDecodeInt1(buffer); - } - case YEAR: - return binaryDecodeInt2(buffer); - case INT2: - if (isUnsignedNumeric(columnDefinitionFlags)) { - return binaryDecodeUnsignedInt2(buffer); - } else { - return binaryDecodeInt2(buffer); - } - case INT3: - if (isUnsignedNumeric(columnDefinitionFlags)) { - return binaryDecodeUnsignedInt3(buffer); - } else { - return binaryDecodeInt3(buffer); - } - case INT4: - if (isUnsignedNumeric(columnDefinitionFlags)) { - return binaryDecodeUnsignedInt4(buffer); - } else { - return binaryDecodeInt4(buffer); - } case INT8: - if (isUnsignedNumeric(columnDefinitionFlags)) { - return binaryDecodeUnsignedInt8(buffer); - } else { - return binaryDecodeInt8(buffer); - } + return binaryDecodeInt8(buffer); + case U_INT8: + return binaryDecodeUnsignedInt8(buffer); + case YEAR: + case INT16: + return binaryDecodeInt16(buffer); + case U_INT16: + return binaryDecodeUnsignedInt16(buffer); + case INT24: + return binaryDecodeInt24(buffer); + case U_INT24: + return binaryDecodeUnsignedInt24(buffer); + case INT32: + return binaryDecodeInt32(buffer); + case U_INT32: + return binaryDecodeUnsignedInt32(buffer); + case INT64: + return binaryDecodeInt64(buffer); + case U_INT64: + return binaryDecodeUnsignedInt64(buffer); case FLOAT: return binaryDecodeFloat(buffer); case DOUBLE: @@ -246,11 +233,22 @@ public static Object decodeBinary(DataType dataType, int collationId, int column return binaryDecodeJson(collationId, buffer); case GEOMETRY: return binaryDecodeGeometry(buffer); + case BINARY: + case VARBINARY: + case TINY_BLOB: + case BLOB: + case MEDIUM_BLOB: + case LONG_BLOB: + return binaryDecodeBlob(buffer); case STRING: case VARSTRING: - case BLOB: + case TINY_TEXT: + case TEXT: + case MEDIUM_TEXT: + case LONG_TEXT: + return binaryDecodeText(collationId, buffer); default: - return binaryDecodeBlobOrText(collationId, columnDefinitionFlags, buffer); + return binaryDecodeBlobOrText(collationId, buffer); } } @@ -260,19 +258,19 @@ public static DataType inferDataTypeByEncodingValue(Object value) { return DataType.NULL; } else if (value instanceof Byte) { // ProtocolBinary::MYSQL_TYPE_TINY - return DataType.INT1; + return DataType.INT8; } else if (value instanceof Boolean) { // ProtocolBinary::MYSQL_TYPE_TINY - return DataType.INT1; + return DataType.INT8; } else if (value instanceof Short) { // ProtocolBinary::MYSQL_TYPE_SHORT, ProtocolBinary::MYSQL_TYPE_YEAR - return DataType.INT2; + return DataType.INT16; } else if (value instanceof Integer) { // ProtocolBinary::MYSQL_TYPE_LONG, ProtocolBinary::MYSQL_TYPE_INT24 - return DataType.INT4; + return DataType.INT32; } else if (value instanceof Long) { // ProtocolBinary::MYSQL_TYPE_LONGLONG - return DataType.INT8; + return DataType.INT64; } else if (value instanceof Double) { // ProtocolBinary::MYSQL_TYPE_DOUBLE return DataType.DOUBLE; @@ -310,23 +308,23 @@ public static DataType inferDataTypeByEncodingValue(Object value) { } } - private static void binaryEncodeInt1(Number value, ByteBuf buffer) { + private static void binaryEncodeInt8(Number value, ByteBuf buffer) { buffer.writeByte(value.byteValue()); } - private static void binaryEncodeInt2(Number value, ByteBuf buffer) { + private static void binaryEncodeInt16(Number value, ByteBuf buffer) { buffer.writeShortLE(value.intValue()); } - private static void binaryEncodeInt3(Number value, ByteBuf buffer) { + private static void binaryEncodeInt24(Number value, ByteBuf buffer) { buffer.writeMediumLE(value.intValue()); } - private static void binaryEncodeInt4(Number value, ByteBuf buffer) { + private static void binaryEncodeInt32(Number value, ByteBuf buffer) { buffer.writeIntLE(value.intValue()); } - private static void binaryEncodeInt8(Number value, ByteBuf buffer) { + private static void binaryEncodeInt64(Number value, ByteBuf buffer) { buffer.writeLongLE(value.longValue()); } @@ -471,43 +469,43 @@ private static void binaryEncodeJson(Object value, ByteBuf buffer, Charset chars BufferUtils.writeLengthEncodedString(buffer, Json.encode(value), charset); } - private static Byte binaryDecodeInt1(ByteBuf buffer) { + private static Byte binaryDecodeInt8(ByteBuf buffer) { return buffer.readByte(); } - private static Short binaryDecodeUnsignedInt1(ByteBuf buffer) { + private static Short binaryDecodeUnsignedInt8(ByteBuf buffer) { return buffer.readUnsignedByte(); } - private static Short binaryDecodeInt2(ByteBuf buffer) { + private static Short binaryDecodeInt16(ByteBuf buffer) { return buffer.readShortLE(); } - private static Integer binaryDecodeUnsignedInt2(ByteBuf buffer) { + private static Integer binaryDecodeUnsignedInt16(ByteBuf buffer) { return buffer.readUnsignedShortLE(); } - private static Integer binaryDecodeInt3(ByteBuf buffer) { + private static Integer binaryDecodeInt24(ByteBuf buffer) { return buffer.readIntLE(); } - private static Integer binaryDecodeUnsignedInt3(ByteBuf buffer) { + private static Integer binaryDecodeUnsignedInt24(ByteBuf buffer) { return buffer.readIntLE() & 0xFFFFFF; } - private static Integer binaryDecodeInt4(ByteBuf buffer) { + private static Integer binaryDecodeInt32(ByteBuf buffer) { return buffer.readIntLE(); } - private static Long binaryDecodeUnsignedInt4(ByteBuf buffer) { + private static Long binaryDecodeUnsignedInt32(ByteBuf buffer) { return buffer.readUnsignedIntLE(); } - private static Long binaryDecodeInt8(ByteBuf buffer) { + private static Long binaryDecodeInt64(ByteBuf buffer) { return buffer.readLongLE(); } - private static Numeric binaryDecodeUnsignedInt8(ByteBuf buffer) { + private static Numeric binaryDecodeUnsignedInt64(ByteBuf buffer) { byte[] bigIntValue = new byte[8]; buffer.readBytes(bigIntValue); // little endian for (int i = 0; i < 4; i++) { @@ -541,12 +539,11 @@ private static Numeric binaryDecodeNumeric(int collationId, ByteBuf buffer) { return Numeric.parse(BufferUtils.readLengthEncodedString(buffer, charset)); } - private static Object binaryDecodeBlobOrText(int collationId, int columnDefinitionFlags, ByteBuf buffer) { + private static Object binaryDecodeBlobOrText(int collationId, ByteBuf buffer) { if (collationId == MySQLCollation.binary.collationId()) { return binaryDecodeBlob(buffer); } else { - Charset charset = MySQLCollation.getJavaCharsetByCollationId(collationId); - return binaryDecodeText(charset, buffer); + return binaryDecodeText(collationId, buffer); } } @@ -559,7 +556,8 @@ private static Buffer binaryDecodeBlob(ByteBuf buffer) { return Buffer.buffer(copy); } - private static String binaryDecodeText(Charset charset, ByteBuf buffer) { + private static String binaryDecodeText(int collationId, ByteBuf buffer) { + Charset charset = MySQLCollation.getJavaCharsetByCollationId(collationId); return BufferUtils.readLengthEncodedString(buffer, charset); } @@ -637,23 +635,23 @@ private static Object binaryDecodeJson(int collationId, ByteBuf buffer) { return result; } - private static Byte textDecodeInt1(ByteBuf buffer, int index, int length) { + private static Byte textDecodeInt8(ByteBuf buffer, int index, int length) { return (byte) CommonCodec.decodeDecStringToLong(index, length, buffer); } - private static Short textDecodeInt2(ByteBuf buffer, int index, int length) { + private static Short textDecodeInt16(ByteBuf buffer, int index, int length) { return (short) CommonCodec.decodeDecStringToLong(index, length, buffer); } - private static Integer textDecodeInt3(ByteBuf buffer, int index, int length) { + private static Integer textDecodeInt24(ByteBuf buffer, int index, int length) { return (int) CommonCodec.decodeDecStringToLong(index, length, buffer); } - private static Integer textDecodeInt4(ByteBuf buffer, int index, int length) { + private static Integer textDecodeInt32(ByteBuf buffer, int index, int length) { return (int) CommonCodec.decodeDecStringToLong(index, length, buffer); } - private static Long textDecodeInt8(ByteBuf buffer, int index, int length) { + private static Long textDecodeInt64(ByteBuf buffer, int index, int length) { return CommonCodec.decodeDecStringToLong(index, length, buffer); } @@ -676,13 +674,11 @@ private static Number textDecodeNUMERIC(int collationId, ByteBuf buff, int index return Numeric.parse(buff.toString(index, length, charset)); } - private static Object textDecodeBlobOrText(int collationId, int columnDefinitionFlags, - ByteBuf buffer, int index, int length) { + private static Object textDecodeBlobOrText(int collationId, ByteBuf buffer, int index, int length) { if (collationId == MySQLCollation.binary.collationId()) { return textDecodeBlob(buffer, index, length); } else { - Charset charset = MySQLCollation.getJavaCharsetByCollationId(collationId); - return textDecodeText(charset, buffer, index, length); + return textDecodeText(collationId, buffer, index, length); } } @@ -692,7 +688,8 @@ private static Buffer textDecodeBlob(ByteBuf buffer, int index, int length) { return Buffer.buffer(copy); } - private static String textDecodeText(Charset charset, ByteBuf buffer, int index, int length) { + private static String textDecodeText(int collationId, ByteBuf buffer, int index, int length) { + Charset charset = MySQLCollation.getJavaCharsetByCollationId(collationId); return buffer.toString(index, length, charset); } @@ -774,10 +771,6 @@ private static Object textDecodeJson(int collationId, ByteBuf buffer, int index, return value; } - private static boolean isUnsignedNumeric(int columnDefinitionFlags) { - return (columnDefinitionFlags & ColumnDefinition.ColumnDefinitionFlags.UNSIGNED_FLAG) != 0; - } - private static Long decodeBit(ByteBuf buffer, int index, int length) { byte[] value = new byte[length]; buffer.getBytes(index, value, 0, length); diff --git a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/protocol/ColumnDefinition.java b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/protocol/ColumnDefinition.java index 27de4a41d..0e3381ea1 100644 --- a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/protocol/ColumnDefinition.java +++ b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/protocol/ColumnDefinition.java @@ -63,7 +63,7 @@ public String typeName() { @Override public JDBCType jdbcType() { - return type.jdbcType; + return type.getJdbcType(); } @Override @@ -82,33 +82,33 @@ public String toString() { */ @SuppressWarnings("unused") public static final class ColumnType { - public static final int MYSQL_TYPE_DECIMAL = 0x00; - public static final int MYSQL_TYPE_TINY = 0x01; - public static final int MYSQL_TYPE_SHORT = 0x02; - public static final int MYSQL_TYPE_LONG = 0x03; - public static final int MYSQL_TYPE_FLOAT = 0x04; - public static final int MYSQL_TYPE_DOUBLE = 0x05; - public static final int MYSQL_TYPE_NULL = 0x06; - public static final int MYSQL_TYPE_TIMESTAMP = 0x07; - public static final int MYSQL_TYPE_LONGLONG = 0x08; - public static final int MYSQL_TYPE_INT24 = 0x09; - public static final int MYSQL_TYPE_DATE = 0x0A; - public static final int MYSQL_TYPE_TIME = 0x0B; - public static final int MYSQL_TYPE_DATETIME = 0x0C; - public static final int MYSQL_TYPE_YEAR = 0x0D; - public static final int MYSQL_TYPE_VARCHAR = 0x0F; - public static final int MYSQL_TYPE_BIT = 0x10; - public static final int MYSQL_TYPE_JSON = 0xF5; - public static final int MYSQL_TYPE_NEWDECIMAL = 0xF6; - public static final int MYSQL_TYPE_ENUM = 0xF7; - public static final int MYSQL_TYPE_SET = 0xF8; - public static final int MYSQL_TYPE_TINY_BLOB = 0xF9; - public static final int MYSQL_TYPE_MEDIUM_BLOB = 0xFA; - public static final int MYSQL_TYPE_LONG_BLOB = 0xFB; - public static final int MYSQL_TYPE_BLOB = 0xFC; - public static final int MYSQL_TYPE_VAR_STRING = 0xFD; - public static final int MYSQL_TYPE_STRING = 0xFE; - public static final int MYSQL_TYPE_GEOMETRY = 0xFF; + public static final short MYSQL_TYPE_DECIMAL = 0x00; + public static final short MYSQL_TYPE_TINY = 0x01; + public static final short MYSQL_TYPE_SHORT = 0x02; + public static final short MYSQL_TYPE_LONG = 0x03; + public static final short MYSQL_TYPE_FLOAT = 0x04; + public static final short MYSQL_TYPE_DOUBLE = 0x05; + public static final short MYSQL_TYPE_NULL = 0x06; + public static final short MYSQL_TYPE_TIMESTAMP = 0x07; + public static final short MYSQL_TYPE_LONGLONG = 0x08; + public static final short MYSQL_TYPE_INT24 = 0x09; + public static final short MYSQL_TYPE_DATE = 0x0A; + public static final short MYSQL_TYPE_TIME = 0x0B; + public static final short MYSQL_TYPE_DATETIME = 0x0C; + public static final short MYSQL_TYPE_YEAR = 0x0D; + public static final short MYSQL_TYPE_VARCHAR = 0x0F; + public static final short MYSQL_TYPE_BIT = 0x10; + public static final short MYSQL_TYPE_JSON = 0xF5; + public static final short MYSQL_TYPE_NEWDECIMAL = 0xF6; + public static final short MYSQL_TYPE_ENUM = 0xF7; + public static final short MYSQL_TYPE_SET = 0xF8; + public static final short MYSQL_TYPE_TINY_BLOB = 0xF9; + public static final short MYSQL_TYPE_MEDIUM_BLOB = 0xFA; + public static final short MYSQL_TYPE_LONG_BLOB = 0xFB; + public static final short MYSQL_TYPE_BLOB = 0xFC; + public static final short MYSQL_TYPE_VAR_STRING = 0xFD; + public static final short MYSQL_TYPE_STRING = 0xFE; + public static final short MYSQL_TYPE_GEOMETRY = 0xFF; /* Internal to MySQL Server diff --git a/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/data/SpatialDataTypeCodecTestBase.java b/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/data/SpatialDataTypeCodecTestBase.java index 65182b5f0..987ece60c 100644 --- a/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/data/SpatialDataTypeCodecTestBase.java +++ b/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/data/SpatialDataTypeCodecTestBase.java @@ -17,6 +17,7 @@ import io.vertx.sqlclient.RowSet; import org.junit.Test; +import java.sql.JDBCType; import java.util.List; import java.util.function.Consumer; @@ -24,6 +25,8 @@ public abstract class SpatialDataTypeCodecTestBase extends MySQLDataTypeTestBase @Test public void testDecodePoint(TestContext ctx) { testDecodeGeometry(ctx, "SELECT ST_GeometryFromText('POINT(1.5 5.1)', 0) AS test_geometry;", result -> { + ctx.assertEquals(result.columnDescriptors().get(0).typeName(), "GEOMETRY"); + ctx.assertEquals(result.columnDescriptors().get(0).jdbcType(), JDBCType.OTHER); Row row = result.iterator().next(); Point point = row.get(Point.class, 0); ctx.assertEquals(0L, point.getSRID()); @@ -35,6 +38,8 @@ public void testDecodePoint(TestContext ctx) { @Test public void testDecodeLineString(TestContext ctx) { testDecodeGeometry(ctx, "SELECT ST_GeometryFromText('LINESTRING(0 0,1 1,2 2)', 0) AS test_geometry;", result -> { + ctx.assertEquals(result.columnDescriptors().get(0).typeName(), "GEOMETRY"); + ctx.assertEquals(result.columnDescriptors().get(0).jdbcType(), JDBCType.OTHER); Row row = result.iterator().next(); LineString lineString = row.get(LineString.class, 0); ctx.assertEquals(0L, lineString.getSRID()); @@ -52,6 +57,8 @@ public void testDecodeLineString(TestContext ctx) { @Test public void testDecodePolygon(TestContext ctx) { testDecodeGeometry(ctx, "SELECT ST_GeometryFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5))', 0) AS test_geometry;", result -> { + ctx.assertEquals(result.columnDescriptors().get(0).typeName(), "GEOMETRY"); + ctx.assertEquals(result.columnDescriptors().get(0).jdbcType(), JDBCType.OTHER); Row row = result.iterator().next(); Polygon polygon = row.get(Polygon.class, 0); ctx.assertEquals(0L, polygon.getSRID()); @@ -88,6 +95,8 @@ public void testDecodePolygon(TestContext ctx) { @Test public void testDecodeMultiPoint(TestContext ctx) { testDecodeGeometry(ctx, "SELECT ST_GeometryFromText('MULTIPOINT(0 0,1 1,2 2)', 0) AS test_geometry;", result -> { + ctx.assertEquals(result.columnDescriptors().get(0).typeName(), "GEOMETRY"); + ctx.assertEquals(result.columnDescriptors().get(0).jdbcType(), JDBCType.OTHER); Row row = result.iterator().next(); MultiPoint multiPoint = row.get(MultiPoint.class, 0); ctx.assertEquals(0L, multiPoint.getSRID()); @@ -105,6 +114,8 @@ public void testDecodeMultiPoint(TestContext ctx) { @Test public void testDecodeMultiLineString(TestContext ctx) { testDecodeGeometry(ctx, "SELECT ST_GeometryFromText('MULTILINESTRING((1 1,2 2,3 3),(4 4,5 5))', 0) AS test_geometry;", result -> { + ctx.assertEquals(result.columnDescriptors().get(0).typeName(), "GEOMETRY"); + ctx.assertEquals(result.columnDescriptors().get(0).jdbcType(), JDBCType.OTHER); Row row = result.iterator().next(); MultiLineString multiLineString = row.get(MultiLineString.class, 0); ctx.assertEquals(0L, multiLineString.getSRID()); @@ -131,6 +142,8 @@ public void testDecodeMultiLineString(TestContext ctx) { @Test public void testDecodeMultiPolygon(TestContext ctx) { testDecodeGeometry(ctx, "SELECT ST_GeometryFromText('MULTIPOLYGON(((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1)))', 0) AS test_geometry;", result -> { + ctx.assertEquals(result.columnDescriptors().get(0).typeName(), "GEOMETRY"); + ctx.assertEquals(result.columnDescriptors().get(0).jdbcType(), JDBCType.OTHER); Row row = result.iterator().next(); MultiPolygon multiPolygon = row.get(MultiPolygon.class, 0); ctx.assertEquals(0L, multiPolygon.getSRID()); @@ -170,6 +183,8 @@ public void testDecodeMultiPolygon(TestContext ctx) { @Test public void testDecodeGeometryCollection(TestContext ctx) { testDecodeGeometry(ctx, "SELECT ST_GeometryFromText('GEOMETRYCOLLECTION(Point(1 1),LineString(2 2, 3 3))', 0) AS test_geometry;", result -> { + ctx.assertEquals(result.columnDescriptors().get(0).typeName(), "GEOMETRY"); + ctx.assertEquals(result.columnDescriptors().get(0).jdbcType(), JDBCType.OTHER); Row row = result.iterator().next(); GeometryCollection geometryCollection = row.get(GeometryCollection.class, 0); ctx.assertEquals(0L, geometryCollection.getSRID()); diff --git a/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/tck/MySQLBinaryDataTypeDecodeTest.java b/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/tck/MySQLBinaryDataTypeDecodeTest.java index e7451f402..22f6e5dc2 100644 --- a/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/tck/MySQLBinaryDataTypeDecodeTest.java +++ b/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/tck/MySQLBinaryDataTypeDecodeTest.java @@ -131,6 +131,81 @@ public void testSelectAll(TestContext ctx) { ctx.assertEquals(Duration.ofHours(18).plusMinutes(45).plusSeconds(2), row.getValue("test_time")); conn.close(); })); - })); - } + })); + } + + @Test + @Override + public void testFloat4(TestContext ctx) { + testDecodeGeneric(ctx, "test_float_4", Float.class, JDBCType.FLOAT, 3.40282e38F); + } + + @Test + @Override + public void testChar(TestContext ctx) { + testDecodeGeneric(ctx, "test_char", String.class, JDBCType.CHAR, "testchar"); + } + + @Test + public void test_jdbc_type(TestContext ctx) { + connector.connect(ctx.asyncAssertSuccess(conn -> { + conn + .query("SELECT * from datatype where id = 1") + .execute() + .onComplete(ctx.asyncAssertSuccess(result -> { + ctx.assertEquals(1, result.size()); + + ctx.assertEquals(result.columnDescriptors().get(0).name(), "id"); + ctx.assertEquals(result.columnDescriptors().get(0).jdbcType(), JDBCType.INTEGER); + ctx.assertEquals(result.columnDescriptors().get(1).name(), "Binary"); + ctx.assertEquals(result.columnDescriptors().get(1).jdbcType(), JDBCType.BINARY); + ctx.assertEquals(result.columnDescriptors().get(2).name(), "VarBinary"); + ctx.assertEquals(result.columnDescriptors().get(2).jdbcType(), JDBCType.VARBINARY); + ctx.assertEquals(result.columnDescriptors().get(3).name(), "TinyBlob"); + ctx.assertEquals(result.columnDescriptors().get(3).jdbcType(), JDBCType.BLOB); + ctx.assertEquals(result.columnDescriptors().get(4).name(), "Blob"); + ctx.assertEquals(result.columnDescriptors().get(4).jdbcType(), JDBCType.BLOB); + ctx.assertEquals(result.columnDescriptors().get(5).name(), "MediumBlob"); + ctx.assertEquals(result.columnDescriptors().get(5).jdbcType(), JDBCType.BLOB); + ctx.assertEquals(result.columnDescriptors().get(6).name(), "LongBlob"); + ctx.assertEquals(result.columnDescriptors().get(6).jdbcType(), JDBCType.BLOB); + ctx.assertEquals(result.columnDescriptors().get(7).name(), "TinyText"); + ctx.assertEquals(result.columnDescriptors().get(7).jdbcType(), JDBCType.CLOB); + ctx.assertEquals(result.columnDescriptors().get(8).name(), "Text"); + ctx.assertEquals(result.columnDescriptors().get(8).jdbcType(), JDBCType.CLOB); + ctx.assertEquals(result.columnDescriptors().get(9).name(), "MediumText"); + ctx.assertEquals(result.columnDescriptors().get(9).jdbcType(), JDBCType.CLOB); + ctx.assertEquals(result.columnDescriptors().get(10).name(), "LongText"); + ctx.assertEquals(result.columnDescriptors().get(10).jdbcType(), JDBCType.CLOB); + ctx.assertEquals(result.columnDescriptors().get(11).name(), "test_enum"); + ctx.assertEquals(result.columnDescriptors().get(11).jdbcType(), JDBCType.CHAR); + ctx.assertEquals(result.columnDescriptors().get(12).name(), "test_set"); + ctx.assertEquals(result.columnDescriptors().get(12).jdbcType(), JDBCType.CHAR); + ctx.assertEquals(result.columnDescriptors().get(13).name(), "test_year"); + ctx.assertEquals(result.columnDescriptors().get(13).jdbcType(), JDBCType.SMALLINT); + ctx.assertEquals(result.columnDescriptors().get(14).name(), "test_timestamp"); + ctx.assertEquals(result.columnDescriptors().get(14).jdbcType(), JDBCType.TIMESTAMP); + ctx.assertEquals(result.columnDescriptors().get(15).name(), "test_datetime"); + ctx.assertEquals(result.columnDescriptors().get(15).jdbcType(), JDBCType.TIMESTAMP); + ctx.assertEquals(result.columnDescriptors().get(16).name(), "test_bit"); + ctx.assertEquals(result.columnDescriptors().get(16).jdbcType(), JDBCType.BIT); + ctx.assertEquals(result.columnDescriptors().get(17).name(), "test_unsigned_tinyint"); + ctx.assertEquals(result.columnDescriptors().get(17).jdbcType(), JDBCType.SMALLINT); + ctx.assertEquals(result.columnDescriptors().get(18).name(), "test_unsigned_smallint"); + ctx.assertEquals(result.columnDescriptors().get(18).jdbcType(), JDBCType.INTEGER); + ctx.assertEquals(result.columnDescriptors().get(19).name(), "test_unsigned_mediumint"); + ctx.assertEquals(result.columnDescriptors().get(19).jdbcType(), JDBCType.INTEGER); + ctx.assertEquals(result.columnDescriptors().get(20).name(), "test_unsigned_int"); + ctx.assertEquals(result.columnDescriptors().get(20).jdbcType(), JDBCType.BIGINT); + ctx.assertEquals(result.columnDescriptors().get(21).name(), "test_unsigned_bigint"); + ctx.assertEquals(result.columnDescriptors().get(21).jdbcType(), JDBCType.NUMERIC); + ctx.assertEquals(result.columnDescriptors().get(22).name(), "test_varchar_binary"); + ctx.assertEquals(result.columnDescriptors().get(22).jdbcType(), JDBCType.VARCHAR); + ctx.assertEquals(result.columnDescriptors().get(23).name(), "test_varchar_with_binary_collation"); + ctx.assertEquals(result.columnDescriptors().get(23).jdbcType(), JDBCType.VARBINARY); + ctx.assertEquals(result.columnDescriptors().get(24).name(), "test_text_binary"); + ctx.assertEquals(result.columnDescriptors().get(24).jdbcType(), JDBCType.CLOB); + })); + })); + } } diff --git a/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/tck/MySQLTextDataTypeDecodeTest.java b/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/tck/MySQLTextDataTypeDecodeTest.java index 1acb2d76e..459b84530 100644 --- a/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/tck/MySQLTextDataTypeDecodeTest.java +++ b/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/tck/MySQLTextDataTypeDecodeTest.java @@ -78,4 +78,67 @@ public void testTime(TestContext ctx) { // MySQL TIME type is mapped to java.time.Duration so we need to override here testDecodeGeneric(ctx, "test_time", Duration.class, Duration.ofHours(18).plusMinutes(45).plusSeconds(2)); } + + @Test + public void test_jdbc_type(TestContext ctx) { + connector.connect(ctx.asyncAssertSuccess(conn -> { + conn + .query("SELECT * from datatype where id = 1") + .execute() + .onComplete(ctx.asyncAssertSuccess(result -> { + ctx.assertEquals(1, result.size()); + + ctx.assertEquals(result.columnDescriptors().get(0).name(), "id"); + ctx.assertEquals(result.columnDescriptors().get(0).jdbcType(), JDBCType.INTEGER); + ctx.assertEquals(result.columnDescriptors().get(1).name(), "Binary"); + ctx.assertEquals(result.columnDescriptors().get(1).jdbcType(), JDBCType.BINARY); + ctx.assertEquals(result.columnDescriptors().get(2).name(), "VarBinary"); + ctx.assertEquals(result.columnDescriptors().get(2).jdbcType(), JDBCType.VARBINARY); + ctx.assertEquals(result.columnDescriptors().get(3).name(), "TinyBlob"); + ctx.assertEquals(result.columnDescriptors().get(3).jdbcType(), JDBCType.BLOB); + ctx.assertEquals(result.columnDescriptors().get(4).name(), "Blob"); + ctx.assertEquals(result.columnDescriptors().get(4).jdbcType(), JDBCType.BLOB); + ctx.assertEquals(result.columnDescriptors().get(5).name(), "MediumBlob"); + ctx.assertEquals(result.columnDescriptors().get(5).jdbcType(), JDBCType.BLOB); + ctx.assertEquals(result.columnDescriptors().get(6).name(), "LongBlob"); + ctx.assertEquals(result.columnDescriptors().get(6).jdbcType(), JDBCType.BLOB); + ctx.assertEquals(result.columnDescriptors().get(7).name(), "TinyText"); + ctx.assertEquals(result.columnDescriptors().get(7).jdbcType(), JDBCType.CLOB); + ctx.assertEquals(result.columnDescriptors().get(8).name(), "Text"); + ctx.assertEquals(result.columnDescriptors().get(8).jdbcType(), JDBCType.CLOB); + ctx.assertEquals(result.columnDescriptors().get(9).name(), "MediumText"); + ctx.assertEquals(result.columnDescriptors().get(9).jdbcType(), JDBCType.CLOB); + ctx.assertEquals(result.columnDescriptors().get(10).name(), "LongText"); + ctx.assertEquals(result.columnDescriptors().get(10).jdbcType(), JDBCType.CLOB); + ctx.assertEquals(result.columnDescriptors().get(11).name(), "test_enum"); + ctx.assertEquals(result.columnDescriptors().get(11).jdbcType(), JDBCType.CHAR); + ctx.assertEquals(result.columnDescriptors().get(12).name(), "test_set"); + ctx.assertEquals(result.columnDescriptors().get(12).jdbcType(), JDBCType.CHAR); + ctx.assertEquals(result.columnDescriptors().get(13).name(), "test_year"); + ctx.assertEquals(result.columnDescriptors().get(13).jdbcType(), JDBCType.SMALLINT); + ctx.assertEquals(result.columnDescriptors().get(14).name(), "test_timestamp"); + ctx.assertEquals(result.columnDescriptors().get(14).jdbcType(), JDBCType.TIMESTAMP); + ctx.assertEquals(result.columnDescriptors().get(15).name(), "test_datetime"); + ctx.assertEquals(result.columnDescriptors().get(15).jdbcType(), JDBCType.TIMESTAMP); + ctx.assertEquals(result.columnDescriptors().get(16).name(), "test_bit"); + ctx.assertEquals(result.columnDescriptors().get(16).jdbcType(), JDBCType.BIT); + ctx.assertEquals(result.columnDescriptors().get(17).name(), "test_unsigned_tinyint"); + ctx.assertEquals(result.columnDescriptors().get(17).jdbcType(), JDBCType.SMALLINT); + ctx.assertEquals(result.columnDescriptors().get(18).name(), "test_unsigned_smallint"); + ctx.assertEquals(result.columnDescriptors().get(18).jdbcType(), JDBCType.INTEGER); + ctx.assertEquals(result.columnDescriptors().get(19).name(), "test_unsigned_mediumint"); + ctx.assertEquals(result.columnDescriptors().get(19).jdbcType(), JDBCType.INTEGER); + ctx.assertEquals(result.columnDescriptors().get(20).name(), "test_unsigned_int"); + ctx.assertEquals(result.columnDescriptors().get(20).jdbcType(), JDBCType.BIGINT); + ctx.assertEquals(result.columnDescriptors().get(21).name(), "test_unsigned_bigint"); + ctx.assertEquals(result.columnDescriptors().get(21).jdbcType(), JDBCType.NUMERIC); + ctx.assertEquals(result.columnDescriptors().get(22).name(), "test_varchar_binary"); + ctx.assertEquals(result.columnDescriptors().get(22).jdbcType(), JDBCType.VARCHAR); + ctx.assertEquals(result.columnDescriptors().get(23).name(), "test_varchar_with_binary_collation"); + ctx.assertEquals(result.columnDescriptors().get(23).jdbcType(), JDBCType.VARBINARY); + ctx.assertEquals(result.columnDescriptors().get(24).name(), "test_text_binary"); + ctx.assertEquals(result.columnDescriptors().get(24).jdbcType(), JDBCType.CLOB); + })); + })); + } }