1 module hunt.database.driver.mysql.impl.codec.DataTypeCodec; 2 3 import hunt.database.driver.mysql.impl.codec.DataType; 4 import hunt.database.driver.mysql.impl.codec.ColumnDefinition; 5 6 import hunt.database.driver.mysql.impl.util.BufferUtils; 7 import hunt.database.base.Numeric; 8 9 import hunt.Exceptions; 10 import hunt.logging; 11 import hunt.net.buffer.ByteBuf; 12 import hunt.net.Exceptions; 13 import hunt.text.Charset; 14 15 import std.conv; 16 import std.concurrency : initOnce; 17 import std.variant; 18 19 /** 20 * 21 */ 22 class DataTypeCodec { 23 // binary codec protocol: https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_binary_resultset.html#sect_protocol_binary_resultset_row_value 24 25 // Sentinel used when an object is refused by the data type 26 static Object REFUSED_SENTINEL() { 27 __gshared Object inst; 28 return initOnce!inst(new Object()); 29 } 30 31 // private static final java.time.format.DateTimeFormatter DATETIME_FORMAT = new DateTimeFormatterBuilder() 32 // .parseCaseInsensitive() 33 // .append(ISO_LOCAL_DATE) 34 // .appendLiteral(' ') 35 // .appendValue(HOUR_OF_DAY, 2) 36 // .appendLiteral(':') 37 // .appendValue(MINUTE_OF_HOUR, 2) 38 // .appendLiteral(':') 39 // .appendValue(SECOND_OF_MINUTE, 2) 40 // .appendFraction(MICRO_OF_SECOND, 0, 6, true) 41 // .toFormatter(); 42 43 static Variant decodeText(DataType dataType, Charset charset, int columnDefinitionFlags, ByteBuf buffer) { 44 int len = cast(int) BufferUtils.readLengthEncodedInteger(buffer); 45 int index = buffer.readerIndex(); 46 47 scope(exit) { 48 buffer.skipBytes(len); 49 } 50 51 bool isBinaryField = isBinaryField(columnDefinitionFlags); 52 53 version(HUNT_DB_DEBUG_MORE) { 54 tracef("dataType=%s, index=%d, len=%d, columnDefinitionFlags=%d, isBinaryField=%s", 55 dataType, index, len, columnDefinitionFlags, isBinaryField); 56 } 57 58 string value = ""; 59 if (isBinaryField) { 60 byte[] data = textDecodeBlob(index, len, buffer); 61 if(data is null) { 62 return Variant(""); 63 } else { 64 return Variant(cast(string)data); 65 } 66 } else { 67 value = textDecodeText(charset, index, len, buffer); 68 } 69 70 version(HUNT_DB_DEBUG_MORE) { 71 byte[] d = new byte[len]; 72 for(int i=0; i< len; i++) { 73 d[i] = buffer.getByte(index + i); 74 } 75 tracef("raw value: %s, bytes: [%(%02X %)]", value, d); 76 } 77 // ByteBuf data = buffer.readSlice(length); 78 switch (dataType) { 79 case DataType.BIT: 80 byte v = buffer.getByte(index); 81 if(v == 1) return Variant(true); 82 return Variant(false); 83 84 case DataType.INT1: 85 return to!(byte)(value).Variant(); 86 87 case DataType.INT2: 88 case DataType.YEAR: 89 return to!short(value).Variant(); 90 91 case DataType.INT3: 92 case DataType.INT4: 93 return to!int(value).Variant(); 94 95 case DataType.INT8: 96 return to!long(value).Variant(); 97 98 case DataType.FLOAT: 99 return to!float(value).Variant(); 100 101 case DataType.DOUBLE: 102 return to!double(value).Variant(); 103 104 // case DataType.NUMERIC: 105 // return textDecodeNUMERIC(charset, data).Variant(); 106 // case DataType.DATE: 107 // return textDecodeDate(charset, data).Variant(); 108 // case DataType.TIME: 109 // return textDecodeTime(charset, data).Variant(); 110 // case DataType.DATETIME: 111 // case DataType.TIMESTAMP: 112 // return textDecodeDateTime(charset, data).Variant(); 113 case DataType.STRING: 114 case DataType.VARSTRING: 115 case DataType.BLOB: 116 default: 117 // if (isBinaryField(columnDefinitionFlags)) { 118 // return textDecodeBlob(index, len, buffer).Variant(); 119 // } else { 120 // return textDecodeText(charset, index, len, buffer).Variant(); 121 // } 122 123 return textDecodeText(charset, index, len, buffer).Variant(); 124 } 125 } 126 127 // //TODO take care of unsigned numeric values here? 128 static void encodeBinary(DataType dataType, Charset charset, ref Variant value, ByteBuf buffer) { 129 switch (dataType) { 130 case DataType.INT1: 131 byte b = 0; 132 if (value.type == typeid(bool)) { 133 if (value.get!bool()) { 134 b = 1; 135 } else { 136 b = 0; 137 } 138 } else { 139 assert(value.type == typeid(byte) || value.type == typeid(ubyte)); 140 b = value.get!byte(); 141 } 142 buffer.writeByte(b); 143 break; 144 145 case DataType.INT2: 146 assert(value.type == typeid(short) || value.type == typeid(short)); 147 buffer.writeShortLE(value.get!short()); 148 break; 149 150 case DataType.INT3: 151 assert(value.type == typeid(int) || value.type == typeid(uint)); 152 buffer.writeMediumLE(value.get!int()); 153 break; 154 155 case DataType.INT4: 156 assert(value.type == typeid(int) || value.type == typeid(uint)); 157 buffer.writeIntLE(value.get!int()); 158 break; 159 160 case DataType.INT8: 161 assert(value.type == typeid(long) || value.type == typeid(ulong)); 162 buffer.writeLongLE(value.get!int()); 163 break; 164 165 case DataType.FLOAT: 166 assert(value.type == typeid(float)); 167 buffer.writeFloatLE(value.get!float()); 168 break; 169 170 case DataType.DOUBLE: 171 assert(value.type == typeid(int) || value.type == typeid(int)); 172 buffer.writeDoubleLE(value.get!double()); 173 break; 174 // case DataType.NUMERIC: 175 // binaryEncodeNumeric(charset, (Numeric) value, buffer); 176 // break; 177 case DataType.BLOB: 178 assert(value.type == typeid(byte[]) || value.type == typeid(ubyte[])); 179 byte[] data = value.get!(byte[])(); 180 BufferUtils.writeLengthEncodedInteger(buffer, cast(int)data.length); 181 buffer.writeBytes(data); 182 break; 183 // case DataType.DATE: 184 // binaryEncodeDate((LocalDate) value, buffer); 185 // break; 186 // case DataType.TIME: 187 // binaryEncodeTime((Duration) value, buffer); 188 // break; 189 // case DataType.DATETIME: 190 // binaryEncodeDatetime((LocalDateTime) value, buffer); 191 // break; 192 case DataType.STRING: 193 case DataType.VARSTRING: 194 default: 195 // binaryEncodeText(charset, string.valueOf(value), buffer); 196 assert(value.type == typeid(string) || value.type == typeid(const(char)[]) 197 || value.type == typeid(immutable(char)[])); 198 BufferUtils.writeLengthEncodedString(buffer, value.get!string(), charset); 199 break; 200 } 201 } 202 203 static Variant decodeBinary(DataType dataType, Charset charset, int columnDefinitionFlags, ByteBuf buffer) { 204 205 switch (dataType) { 206 case DataType.INT1: 207 return buffer.readByte().Variant(); 208 case DataType.YEAR: 209 case DataType.INT2: 210 return buffer.readShortLE().Variant(); 211 case DataType.INT3: 212 case DataType.INT4: 213 return buffer.readIntLE().Variant(); 214 case DataType.INT8: 215 return buffer.readLongLE().Variant(); 216 case DataType.FLOAT: 217 return buffer.readFloatLE().Variant(); 218 case DataType.DOUBLE: 219 return buffer.readDoubleLE().Variant(); 220 // case DataType.NUMERIC: 221 // return binaryDecodeNumeric(charset, buffer).Variant(); 222 // case DataType.DATE: 223 // return binaryDecodeDate(buffer).Variant(); 224 // case DataType.TIME: 225 // return binaryDecodeTime(buffer).Variant(); 226 // case DataType.DATETIME: 227 // case DataType.TIMESTAMP: 228 // return binaryDecodeDatetime(buffer).Variant(); 229 case DataType.STRING: 230 case DataType.VARSTRING: 231 case DataType.BLOB: 232 default: 233 if (isBinaryField(columnDefinitionFlags)) { 234 return binaryDecodeBlob(buffer).Variant(); 235 } else { 236 return BufferUtils.readLengthEncodedString(buffer, charset).Variant(); 237 } 238 } 239 } 240 241 // static Object prepare(DataType type, Object value) { 242 // switch (type) { 243 // //TODO handle json + unknown? 244 // default: 245 // Class<?> javaType = type.binaryType; 246 // return value is null || javaType.isInstance(value) ? value : REFUSED_SENTINEL; 247 // } 248 // } 249 250 // private static void binaryEncodeInt1(Number value, ByteBuf buffer) { 251 // buffer.writeByte(value.byteValue()); 252 // } 253 254 // private static void binaryEncodeInt2(Number value, ByteBuf buffer) { 255 // buffer.writeShortLE(value.intValue()); 256 // } 257 258 // private static void binaryEncodeInt3(Number value, ByteBuf buffer) { 259 // buffer.writeMediumLE(value.intValue()); 260 // } 261 262 // private static void binaryEncodeInt4(Number value, ByteBuf buffer) { 263 // buffer.writeIntLE(value.intValue()); 264 // } 265 266 // private static void binaryEncodeInt8(Number value, ByteBuf buffer) { 267 // buffer.writeLongLE(value.longValue()); 268 // } 269 270 // private static void binaryEncodeFloat(Number value, ByteBuf buffer) { 271 // buffer.writeFloatLE(value.floatValue()); 272 // } 273 274 // private static void binaryEncodeDouble(Number value, ByteBuf buffer) { 275 // buffer.writeDoubleLE(value.doubleValue()); 276 // } 277 278 // private static void binaryEncodeNumeric(Charset charset, Numeric value, ByteBuf buffer) { 279 // BufferUtils.writeLengthEncodedString(buffer, value.toString(), charset); 280 // } 281 282 // private static void binaryEncodeText(Charset charset, string value, ByteBuf buffer) { 283 // BufferUtils.writeLengthEncodedString(buffer, value, charset); 284 // } 285 286 // private static void binaryEncodeBlob(Buffer value, ByteBuf buffer) { 287 // BufferUtils.writeLengthEncodedInteger(buffer, value.length()); 288 // buffer.writeBytes(value.getByteBuf()); 289 // } 290 291 // private static void binaryEncodeDate(LocalDate value, ByteBuf buffer) { 292 // buffer.writeByte(4); 293 // buffer.writeShortLE(value.getYear()); 294 // buffer.writeByte(value.getMonthValue()); 295 // buffer.writeByte(value.getDayOfMonth()); 296 // } 297 298 // private static void binaryEncodeTime(Duration value, ByteBuf buffer) { 299 // long secondsOfDuration = value.getSeconds(); 300 // int nanosOfDuration = value.getNano(); 301 // if (secondsOfDuration == 0 && nanosOfDuration == 0) { 302 // buffer.writeByte(0); 303 // return; 304 // } 305 // byte isNegative = 0; 306 // if (secondsOfDuration < 0) { 307 // isNegative = 1; 308 // secondsOfDuration = -secondsOfDuration; 309 // } 310 311 // int days = (int) (secondsOfDuration / 86400); 312 // int secondsOfADay = (int) (secondsOfDuration % 86400); 313 // int hour = secondsOfADay / 3600; 314 // int minute = ((secondsOfADay % 3600) / 60); 315 // int second = secondsOfADay % 60; 316 317 // if (nanosOfDuration == 0) { 318 // buffer.writeByte(8); 319 // buffer.writeByte(isNegative); 320 // buffer.writeIntLE(days); 321 // buffer.writeByte(hour); 322 // buffer.writeByte(minute); 323 // buffer.writeByte(second); 324 // return; 325 // } 326 327 // int microSecond; 328 // if (isNegative == 1 && nanosOfDuration > 0) { 329 // second = second - 1; 330 // microSecond = (1000_000_000 - nanosOfDuration) / 1000; 331 // } else { 332 // microSecond = nanosOfDuration / 1000; 333 // } 334 335 // buffer.writeByte(12); 336 // buffer.writeByte(isNegative); 337 // buffer.writeIntLE(days); 338 // buffer.writeByte(hour); 339 // buffer.writeByte(minute); 340 // buffer.writeByte(second); 341 // buffer.writeIntLE(microSecond); 342 // } 343 344 // private static void binaryEncodeDatetime(LocalDateTime value, ByteBuf buffer) { 345 // int year = value.getYear(); 346 // int month = value.getMonthValue(); 347 // int day = value.getDayOfMonth(); 348 // int hour = value.getHour(); 349 // int minute = value.getMinute(); 350 // int second = value.getSecond(); 351 // int microsecond = value.getNano() / 1000; 352 353 // // LocalDateTime does not have a zero value of month or day 354 // if (hour == 0 && minute == 0 && second == 0 && microsecond == 0) { 355 // buffer.writeByte(4); 356 // buffer.writeShortLE(year); 357 // buffer.writeByte(month); 358 // buffer.writeByte(day); 359 // } else if (microsecond == 0) { 360 // buffer.writeByte(7); 361 // buffer.writeShortLE(year); 362 // buffer.writeByte(month); 363 // buffer.writeByte(day); 364 // buffer.writeByte(hour); 365 // buffer.writeByte(minute); 366 // buffer.writeByte(second); 367 // } else { 368 // buffer.writeByte(11); 369 // buffer.writeShortLE(year); 370 // buffer.writeByte(month); 371 // buffer.writeByte(day); 372 // buffer.writeByte(hour); 373 // buffer.writeByte(minute); 374 // buffer.writeByte(second); 375 // buffer.writeIntLE(microsecond); 376 // } 377 // } 378 379 // private static Byte binaryDecodeInt1(ByteBuf buffer) { 380 // return buffer.readByte(); 381 // } 382 383 // private static Short binaryDecodeInt2(ByteBuf buffer) { 384 // return buffer.readShortLE(); 385 // } 386 387 // private static Integer binaryDecodeInt3(ByteBuf buffer) { 388 // return buffer.readIntLE(); 389 // } 390 391 // private static Integer binaryDecodeInt4(ByteBuf buffer) { 392 // return buffer.readIntLE(); 393 // } 394 395 // private static Long binaryDecodeInt8(ByteBuf buffer) { 396 // return buffer.readLongLE(); 397 // } 398 399 // private static Float binaryDecodeFloat(ByteBuf buffer) { 400 // return buffer.readFloatLE(); 401 // } 402 403 // private static Double binaryDecodeDouble(ByteBuf buffer) { 404 // return buffer.readDoubleLE(); 405 // } 406 407 // private static Numeric binaryDecodeNumeric(Charset charset, ByteBuf buffer) { 408 // return Numeric.parse(BufferUtils.readLengthEncodedString(buffer, charset)); 409 // } 410 411 // private static Object binaryDecodeBlobOrText(Charset charset, int columnDefinitionFlags, ByteBuf buffer) { 412 // if (isBinaryField(columnDefinitionFlags)) { 413 // return binaryDecodeBlob(buffer); 414 // } else { 415 // return binaryDecodeText(charset, buffer); 416 // } 417 // } 418 419 private static byte[] binaryDecodeBlob(ByteBuf buffer) { 420 int len = cast(int) BufferUtils.readLengthEncodedInteger(buffer); 421 ByteBuf buff = buffer.copy(buffer.readerIndex(), len); 422 buffer.skipBytes(len); 423 return buff.getReadableBytes(); 424 } 425 426 // private static string binaryDecodeText(Charset charset, ByteBuf buffer) { 427 // return BufferUtils.readLengthEncodedString(buffer, charset); 428 // } 429 430 // private static LocalDateTime binaryDecodeDatetime(ByteBuf buffer) { 431 // if (buffer.readableBytes() == 0) { 432 // return null; 433 // } 434 // int length = buffer.readByte(); 435 // if (length == 0) { 436 // // invalid value '0000-00-00' or '0000-00-00 00:00:00' 437 // return null; 438 // } else { 439 // int year = buffer.readShortLE(); 440 // byte month = buffer.readByte(); 441 // byte day = buffer.readByte(); 442 // if (length == 4) { 443 // return LocalDateTime.of(year, month, day, 0, 0, 0); 444 // } 445 // byte hour = buffer.readByte(); 446 // byte minute = buffer.readByte(); 447 // byte second = buffer.readByte(); 448 // if (length == 11) { 449 // int microsecond = buffer.readIntLE(); 450 // return LocalDateTime.of(year, month, day, hour, minute, second, microsecond * 1000); 451 // } else if (length == 7) { 452 // return LocalDateTime.of(year, month, day, hour, minute, second, 0); 453 // } 454 // throw new DecoderException("Invalid Datetime"); 455 // } 456 // } 457 458 // private static LocalDate binaryDecodeDate(ByteBuf buffer) { 459 // return binaryDecodeDatetime(buffer).toLocalDate(); 460 // } 461 462 // private static Duration binaryDecodeTime(ByteBuf buffer) { 463 // byte length = buffer.readByte(); 464 // if (length == 0) { 465 // return Duration.ZERO; 466 // } else { 467 // bool isNegative = (buffer.readByte() == 1); 468 // int days = buffer.readIntLE(); 469 // int hour = buffer.readByte(); 470 // int minute = buffer.readByte(); 471 // int second = buffer.readByte(); 472 // if (isNegative) { 473 // days = -days; 474 // hour = -hour; 475 // minute = -minute; 476 // second = -second; 477 // } 478 479 // if (length == 8) { 480 // return Duration.ofDays(days).plusHours(hour).plusMinutes(minute).plusSeconds(second); 481 // } 482 // if (length == 12) { 483 // long microsecond = buffer.readUnsignedIntLE(); 484 // if (isNegative) { 485 // microsecond = -microsecond; 486 // } 487 // return Duration.ofDays(days).plusHours(hour).plusMinutes(minute).plusSeconds(second).plusNanos(microsecond * 1000); 488 // } 489 // throw new DecoderException("Invalid time format"); 490 // } 491 // } 492 493 // private static Byte textDecodeInt1(Charset charset, ByteBuf buffer) { 494 // return Byte.parseByte(buffer.toString(charset)); 495 // } 496 497 // private static Short textDecodeInt2(Charset charset, ByteBuf buffer) { 498 // return Short.parseShort(buffer.toString(charset)); 499 // } 500 501 // private static Integer textDecodeInt3(Charset charset, ByteBuf buffer) { 502 // return Integer.parseInt(buffer.toString(charset)); 503 // } 504 505 // private static Integer textDecodeInt4(Charset charset, ByteBuf buffer) { 506 // return Integer.parseInt(buffer.toString(charset)); 507 // } 508 509 // private static Long textDecodeInt8(Charset charset, ByteBuf buffer) { 510 // return Long.parseLong(buffer.toString(charset)); 511 // } 512 513 // private static Float textDecodeFloat(Charset charset, ByteBuf buffer) { 514 // return Float.parseFloat(buffer.toString(charset)); 515 // } 516 517 // private static Double textDecodeDouble(Charset charset, ByteBuf buffer) { 518 // return Double.parseDouble(buffer.toString(charset)); 519 // } 520 521 // private static Number textDecodeNUMERIC(Charset charset, ByteBuf buff) { 522 // return Numeric.parse(buff.toString(charset)); 523 // } 524 525 // private static Object textDecodeBlobOrText(Charset charset, int columnDefinitionFlags, 526 // int index, int len, ByteBuf buffer) { 527 // if (isBinaryField(columnDefinitionFlags)) { 528 // return textDecodeBlob(buffer); 529 // } else { 530 // return textDecodeText(charset, buffer); 531 // } 532 // } 533 534 private static byte[] textDecodeBlob(int index, int len, ByteBuf buffer) { 535 ByteBuf buff = buffer.copy(index, len); 536 return buff.getReadableBytes(); 537 } 538 539 private static string textDecodeText(Charset charset, int index, int len, ByteBuf buffer) { 540 return buffer.getCharSequence(index, len, charset); 541 } 542 543 // private static LocalDate textDecodeDate(Charset charset, ByteBuf buffer) { 544 // CharSequence cs = buffer.toString(charset); 545 // return LocalDate.parse(cs); 546 // } 547 548 // private static Duration textDecodeTime(Charset charset, ByteBuf buffer) { 549 // // HH:mm:ss or HHH:mm:ss 550 // string timeString = buffer.toString(charset); 551 // bool isNegative = timeString.charAt(0) == '-'; 552 // if (isNegative) { 553 // timeString = timeString.substring(1); 554 // } 555 556 // string[] timeElements = timeString.split(":"); 557 // if (timeElements.length != 3) { 558 // throw new DecoderException("Invalid time format"); 559 // } 560 561 // int hour = Integer.parseInt(timeElements[0]); 562 // int minute = Integer.parseInt(timeElements[1]); 563 // int second = Integer.parseInt(timeElements[2].substring(0, 2)); 564 // long nanos = 0; 565 // if (timeElements[2].length() > 2) { 566 // double fractionalSecondsPart = Double.parseDouble("0." ~ timeElements[2].substring(3)); 567 // nanos = (long) (1000000000 * fractionalSecondsPart); 568 // } 569 // if (isNegative) { 570 // return Duration.ofHours(-hour).minusMinutes(minute).minusSeconds(second).minusNanos(nanos); 571 // } else { 572 // return Duration.ofHours(hour).plusMinutes(minute).plusSeconds(second).plusNanos(nanos); 573 // } 574 // } 575 576 // private static LocalDateTime textDecodeDateTime(Charset charset, ByteBuf buffer) { 577 // CharSequence cs = buffer.toString(charset); 578 // if (cs.equals("0000-00-00 00:00:00")) { 579 // // Invalid datetime will be converted to zero 580 // return null; 581 // } 582 // return LocalDateTime.parse(cs, DATETIME_FORMAT); 583 // } 584 585 private static bool isBinaryField(int columnDefinitionFlags) { 586 return (columnDefinitionFlags & ColumnDefinitionFlags.BINARY_FLAG) != 0; 587 } 588 }