|
11 | 11 |
|
12 | 12 | package io.vertx.mysqlclient.impl.datatype;
|
13 | 13 |
|
14 |
| -import io.netty.util.collection.IntObjectHashMap; |
15 |
| -import io.netty.util.collection.IntObjectMap; |
| 14 | +import io.netty.util.collection.ShortObjectHashMap; |
| 15 | +import io.netty.util.collection.ShortObjectMap; |
16 | 16 | import io.vertx.core.buffer.Buffer;
|
17 | 17 | import io.vertx.core.impl.logging.Logger;
|
18 | 18 | import io.vertx.core.impl.logging.LoggerFactory;
|
19 | 19 | import io.vertx.mysqlclient.data.spatial.Geometry;
|
| 20 | +import io.vertx.mysqlclient.impl.MySQLCollation; |
20 | 21 | import io.vertx.mysqlclient.impl.protocol.ColumnDefinition;
|
21 | 22 | import io.vertx.sqlclient.data.Numeric;
|
22 | 23 |
|
| 24 | +import java.math.BigInteger; |
23 | 25 | import java.sql.JDBCType;
|
24 | 26 | import java.time.Duration;
|
25 | 27 | import java.time.LocalDate;
|
26 | 28 | import java.time.LocalDateTime;
|
| 29 | +import java.util.Arrays; |
| 30 | +import java.util.List; |
27 | 31 |
|
28 | 32 | public enum DataType {
|
29 |
| - INT1(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY, Byte.class, Byte.class, JDBCType.TINYINT), |
30 |
| - INT2(ColumnDefinition.ColumnType.MYSQL_TYPE_SHORT, Short.class, Short.class, JDBCType.SMALLINT), |
31 |
| - INT3(ColumnDefinition.ColumnType.MYSQL_TYPE_INT24, Integer.class, Integer.class, JDBCType.INTEGER), |
32 |
| - INT4(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG, Integer.class, Integer.class, JDBCType.INTEGER), |
33 |
| - INT8(ColumnDefinition.ColumnType.MYSQL_TYPE_LONGLONG, Long.class, Long.class, JDBCType.BIGINT), |
34 |
| - DOUBLE(ColumnDefinition.ColumnType.MYSQL_TYPE_DOUBLE, Double.class, Double.class, JDBCType.DOUBLE), |
35 |
| - FLOAT(ColumnDefinition.ColumnType.MYSQL_TYPE_FLOAT, Float.class, Float.class, JDBCType.REAL), |
36 |
| - NUMERIC(ColumnDefinition.ColumnType.MYSQL_TYPE_NEWDECIMAL, Numeric.class, Numeric.class, JDBCType.DECIMAL), // DECIMAL |
37 |
| - STRING(ColumnDefinition.ColumnType.MYSQL_TYPE_STRING, Buffer.class, String.class, JDBCType.VARCHAR), // CHAR, BINARY |
38 |
| - VARSTRING(ColumnDefinition.ColumnType.MYSQL_TYPE_VAR_STRING, Buffer.class, String.class, JDBCType.VARCHAR), //VARCHAR, VARBINARY |
39 |
| - TINYBLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY_BLOB, Buffer.class, String.class, JDBCType.BLOB), |
40 |
| - BLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_BLOB, Buffer.class, String.class, JDBCType.BLOB), |
41 |
| - MEDIUMBLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_MEDIUM_BLOB, Buffer.class, String.class, JDBCType.BLOB), |
42 |
| - LONGBLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG_BLOB, Buffer.class, String.class, JDBCType.BLOB), |
43 |
| - DATE(ColumnDefinition.ColumnType.MYSQL_TYPE_DATE, LocalDate.class, LocalDate.class, JDBCType.DATE), |
44 |
| - TIME(ColumnDefinition.ColumnType.MYSQL_TYPE_TIME, Duration.class, Duration.class, JDBCType.TIME), |
45 |
| - DATETIME(ColumnDefinition.ColumnType.MYSQL_TYPE_DATETIME, LocalDateTime.class, LocalDateTime.class, JDBCType.TIMESTAMP), |
46 |
| - YEAR(ColumnDefinition.ColumnType.MYSQL_TYPE_YEAR, Short.class, Short.class, JDBCType.SMALLINT), |
47 |
| - TIMESTAMP(ColumnDefinition.ColumnType.MYSQL_TYPE_TIMESTAMP, LocalDateTime.class, LocalDateTime.class, JDBCType.TIMESTAMP), |
48 |
| - BIT(ColumnDefinition.ColumnType.MYSQL_TYPE_BIT, Long.class, Long.class, JDBCType.BIT), |
49 |
| - JSON(ColumnDefinition.ColumnType.MYSQL_TYPE_JSON, Object.class, Object.class, JDBCType.OTHER), |
50 |
| - GEOMETRY(ColumnDefinition.ColumnType.MYSQL_TYPE_GEOMETRY, Geometry.class, Geometry.class, JDBCType.OTHER), |
51 |
| - NULL(ColumnDefinition.ColumnType.MYSQL_TYPE_NULL, Object.class, Object.class, JDBCType.OTHER), // useful for mariadb prepare statement response |
52 |
| - UNBIND(-1, Object.class, Object.class, JDBCType.OTHER); // useful for binding param values |
| 33 | + |
| 34 | + // unsigned int |
| 35 | + U_INT8(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY, Short.class, JDBCType.SMALLINT), |
| 36 | + U_INT16(ColumnDefinition.ColumnType.MYSQL_TYPE_SHORT, Integer.class, JDBCType.INTEGER), |
| 37 | + U_INT24(ColumnDefinition.ColumnType.MYSQL_TYPE_INT24, Integer.class, JDBCType.INTEGER), |
| 38 | + U_INT32(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG, Long.class, JDBCType.BIGINT), |
| 39 | + U_INT64(ColumnDefinition.ColumnType.MYSQL_TYPE_LONGLONG, BigInteger.class, JDBCType.NUMERIC), |
| 40 | + // signed int |
| 41 | + INT8(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY, Byte.class, JDBCType.TINYINT), |
| 42 | + INT16(ColumnDefinition.ColumnType.MYSQL_TYPE_SHORT, Short.class, JDBCType.SMALLINT), |
| 43 | + INT24(ColumnDefinition.ColumnType.MYSQL_TYPE_INT24, Integer.class, JDBCType.INTEGER), |
| 44 | + INT32(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG, Integer.class, JDBCType.INTEGER), |
| 45 | + INT64(ColumnDefinition.ColumnType.MYSQL_TYPE_LONGLONG, Long.class, JDBCType.BIGINT), |
| 46 | + // numeric |
| 47 | + BIT(ColumnDefinition.ColumnType.MYSQL_TYPE_BIT, Long.class, JDBCType.BIT), |
| 48 | + DOUBLE(ColumnDefinition.ColumnType.MYSQL_TYPE_DOUBLE, Double.class, JDBCType.DOUBLE), |
| 49 | + FLOAT(ColumnDefinition.ColumnType.MYSQL_TYPE_FLOAT, Float.class, JDBCType.FLOAT), |
| 50 | + NUMERIC(ColumnDefinition.ColumnType.MYSQL_TYPE_NEWDECIMAL, Numeric.class, JDBCType.DECIMAL), |
| 51 | + // string |
| 52 | + STRING(ColumnDefinition.ColumnType.MYSQL_TYPE_STRING, String.class, JDBCType.CHAR), |
| 53 | + VARSTRING(ColumnDefinition.ColumnType.MYSQL_TYPE_VAR_STRING, String.class, JDBCType.VARCHAR), |
| 54 | + // clob |
| 55 | + TINY_TEXT(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY_BLOB, String.class, JDBCType.CLOB), |
| 56 | + TEXT(ColumnDefinition.ColumnType.MYSQL_TYPE_BLOB, String.class, JDBCType.CLOB), |
| 57 | + MEDIUM_TEXT(ColumnDefinition.ColumnType.MYSQL_TYPE_MEDIUM_BLOB, String.class, JDBCType.CLOB), |
| 58 | + LONG_TEXT(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG_BLOB, String.class, JDBCType.CLOB), |
| 59 | + // binary |
| 60 | + BINARY(ColumnDefinition.ColumnType.MYSQL_TYPE_STRING, Buffer.class, JDBCType.BINARY), |
| 61 | + VARBINARY(ColumnDefinition.ColumnType.MYSQL_TYPE_VAR_STRING, Buffer.class, JDBCType.VARBINARY), |
| 62 | + // blob |
| 63 | + TINY_BLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY_BLOB, Buffer.class, JDBCType.BLOB), |
| 64 | + BLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_BLOB, Buffer.class, JDBCType.BLOB), |
| 65 | + MEDIUM_BLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_MEDIUM_BLOB, Buffer.class, JDBCType.BLOB), |
| 66 | + LONG_BLOB(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG_BLOB, Buffer.class, JDBCType.BLOB), |
| 67 | + // time |
| 68 | + DATE(ColumnDefinition.ColumnType.MYSQL_TYPE_DATE, LocalDate.class, JDBCType.DATE), |
| 69 | + TIME(ColumnDefinition.ColumnType.MYSQL_TYPE_TIME, Duration.class, JDBCType.TIME), |
| 70 | + DATETIME(ColumnDefinition.ColumnType.MYSQL_TYPE_DATETIME, LocalDateTime.class, JDBCType.TIMESTAMP), |
| 71 | + YEAR(ColumnDefinition.ColumnType.MYSQL_TYPE_YEAR, Short.class, JDBCType.SMALLINT), |
| 72 | + TIMESTAMP(ColumnDefinition.ColumnType.MYSQL_TYPE_TIMESTAMP, LocalDateTime.class, JDBCType.TIMESTAMP), |
| 73 | + |
| 74 | + JSON(ColumnDefinition.ColumnType.MYSQL_TYPE_JSON, Object.class, JDBCType.OTHER), |
| 75 | + GEOMETRY(ColumnDefinition.ColumnType.MYSQL_TYPE_GEOMETRY, Geometry.class, JDBCType.OTHER), |
| 76 | + NULL(ColumnDefinition.ColumnType.MYSQL_TYPE_NULL, Object.class, JDBCType.OTHER), // useful for mariadb prepare statement response |
| 77 | + UNBIND((short) -1, Object.class, JDBCType.OTHER); // useful for binding param values |
| 78 | + ; |
53 | 79 |
|
54 | 80 | private static final Logger LOGGER = LoggerFactory.getLogger(DataType.class);
|
55 | 81 |
|
56 |
| - private static IntObjectMap<DataType> idToDataType = new IntObjectHashMap<>(); |
| 82 | + // protocol id |
| 83 | + private final short columnType; |
57 | 84 |
|
58 |
| - static { |
59 |
| - for (DataType dataType : values()) { |
60 |
| - idToDataType.put(dataType.id, dataType); |
61 |
| - } |
62 |
| - } |
| 85 | + private final Class<?> javaType; |
63 | 86 |
|
64 |
| - public final int id; |
65 |
| - public final Class<?> binaryType; |
66 |
| - public final Class<?> textType; |
67 |
| - public final JDBCType jdbcType; |
| 87 | + private final JDBCType jdbcType; |
68 | 88 |
|
69 |
| - DataType(int id, Class<?> binaryType, Class<?> textType, JDBCType jdbcType) { |
70 |
| - this.id = id; |
71 |
| - this.binaryType = binaryType; |
72 |
| - this.textType = textType; |
| 89 | + DataType(short columnType, Class<?> javaType, JDBCType jdbcType) { |
| 90 | + this.columnType = columnType; |
| 91 | + this.javaType = javaType; |
73 | 92 | this.jdbcType = jdbcType;
|
74 | 93 | }
|
75 | 94 |
|
76 |
| - public static DataType valueOf(int value) { |
77 |
| - DataType dataType = idToDataType.get(value); |
| 95 | + public int getColumnType() { |
| 96 | + return columnType; |
| 97 | + } |
| 98 | + |
| 99 | + public Class<?> getJavaType() { |
| 100 | + return javaType; |
| 101 | + } |
| 102 | + |
| 103 | + public JDBCType getJdbcType() { |
| 104 | + return jdbcType; |
| 105 | + } |
| 106 | + |
| 107 | + public static DataType parseDataType(short type, int characterSet, int flags) { |
| 108 | + // integer |
| 109 | + if (COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.containsKey(type)) { |
| 110 | + return isUnsignedNumeric(flags) ? COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.get(type).get(0) : COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.get(type).get(1); |
| 111 | + } |
| 112 | + |
| 113 | + // string |
| 114 | + if (COLUMN_TYPE_TO_STRING_TYPE_MAPPING.containsKey(type)) { |
| 115 | + return isText(characterSet) ? COLUMN_TYPE_TO_STRING_TYPE_MAPPING.get(type).get(0) : COLUMN_TYPE_TO_STRING_TYPE_MAPPING.get(type).get(1); |
| 116 | + } |
| 117 | + |
| 118 | + // others |
| 119 | + DataType dataType = COLUMN_TYPE_TO_DATA_TYPE_MAPPING.get(type); |
78 | 120 | if (dataType == null) {
|
79 |
| - LOGGER.warn(String.format("MySQL data type Id =[%d] not handled - using string type instead", value)); |
| 121 | + LOGGER.warn(String.format("MySQL data type Id =[%d] not handled - using string type instead", type)); |
80 | 122 | return STRING;
|
81 | 123 | } else {
|
82 | 124 | return dataType;
|
83 | 125 | }
|
84 | 126 | }
|
| 127 | + |
| 128 | + private static final ShortObjectMap<List<DataType>> COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING; |
| 129 | + private static final ShortObjectMap<List<DataType>> COLUMN_TYPE_TO_STRING_TYPE_MAPPING; |
| 130 | + private static final ShortObjectMap<DataType> COLUMN_TYPE_TO_DATA_TYPE_MAPPING; |
| 131 | + |
| 132 | + static { |
| 133 | + // integer |
| 134 | + // column type -> uint, int |
| 135 | + COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING = new ShortObjectHashMap<>(5, 1.0f); |
| 136 | + COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY, Arrays.asList(U_INT8, INT8)); |
| 137 | + COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_SHORT, Arrays.asList(U_INT16, INT16)); |
| 138 | + COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_INT24, Arrays.asList(U_INT24, INT24)); |
| 139 | + COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG, Arrays.asList(U_INT32, INT32)); |
| 140 | + COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_LONGLONG, Arrays.asList(U_INT64, INT64)); |
| 141 | + |
| 142 | + // string |
| 143 | + // column type -> clob, blob |
| 144 | + COLUMN_TYPE_TO_STRING_TYPE_MAPPING = new ShortObjectHashMap<>(6, 1.0f); |
| 145 | + COLUMN_TYPE_TO_STRING_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_STRING, Arrays.asList(STRING, BINARY)); |
| 146 | + COLUMN_TYPE_TO_STRING_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_VAR_STRING, Arrays.asList(VARSTRING, VARBINARY)); |
| 147 | + COLUMN_TYPE_TO_STRING_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_TINY_BLOB, Arrays.asList(TINY_TEXT, TINY_BLOB)); |
| 148 | + COLUMN_TYPE_TO_STRING_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_BLOB, Arrays.asList(TEXT, BLOB)); |
| 149 | + COLUMN_TYPE_TO_STRING_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_MEDIUM_BLOB, Arrays.asList(MEDIUM_TEXT, MEDIUM_BLOB)); |
| 150 | + COLUMN_TYPE_TO_STRING_TYPE_MAPPING.put(ColumnDefinition.ColumnType.MYSQL_TYPE_LONG_BLOB, Arrays.asList(LONG_TEXT, LONG_BLOB)); |
| 151 | + |
| 152 | + // others |
| 153 | + COLUMN_TYPE_TO_DATA_TYPE_MAPPING = new ShortObjectHashMap<>(13, 1.0f); |
| 154 | + for (DataType dataType : DataType.values()) { |
| 155 | + if (COLUMN_TYPE_TO_INTEGER_TYPE_MAPPING.containsKey(dataType.columnType) || COLUMN_TYPE_TO_STRING_TYPE_MAPPING.containsKey(dataType.columnType)) { |
| 156 | + continue; |
| 157 | + } |
| 158 | + |
| 159 | + COLUMN_TYPE_TO_DATA_TYPE_MAPPING.put(dataType.columnType, dataType); |
| 160 | + } |
| 161 | + } |
| 162 | + |
| 163 | + private static boolean isText(int collationId) { |
| 164 | + return collationId != MySQLCollation.binary.collationId(); |
| 165 | + } |
| 166 | + |
| 167 | + private static boolean isUnsignedNumeric(int columnDefinitionFlags) { |
| 168 | + return (columnDefinitionFlags & ColumnDefinition.ColumnDefinitionFlags.UNSIGNED_FLAG) != 0; |
| 169 | + } |
| 170 | + |
85 | 171 | }
|
0 commit comments