1 module mysql.type; 2 3 4 import std.algorithm; 5 import std.datetime; 6 import std.traits; 7 8 import mysql.protocol; 9 import mysql.packet; 10 import mysql.exception; 11 12 13 struct MySQLValue { 14 package enum BufferSize = max(ulong.sizeof, (ulong[]).sizeof, MySQLDateTime.sizeof, MySQLTime.sizeof); 15 package this(ColumnTypes type, void* ptr, size_t size) { 16 assert(size <= BufferSize); 17 type_ = type; 18 if (type != ColumnTypes.MYSQL_TYPE_NULL) 19 buffer_[0..size] = (cast(ubyte*)ptr)[0..size]; 20 } 21 22 string toString() const { 23 import std.conv; 24 25 final switch(type_) { 26 case ColumnTypes.MYSQL_TYPE_NULL: 27 return "null"; 28 case ColumnTypes.MYSQL_TYPE_TINY: 29 return to!string(*cast(ubyte*)buffer_.ptr); 30 case ColumnTypes.MYSQL_TYPE_YEAR: 31 case ColumnTypes.MYSQL_TYPE_SHORT: 32 return to!string(*cast(ushort*)buffer_.ptr); 33 case ColumnTypes.MYSQL_TYPE_INT24: 34 case ColumnTypes.MYSQL_TYPE_LONG: 35 return to!string(*cast(uint*)buffer_.ptr); 36 case ColumnTypes.MYSQL_TYPE_LONGLONG: 37 return to!string(*cast(ulong*)buffer_.ptr); 38 case ColumnTypes.MYSQL_TYPE_FLOAT: 39 return to!string(*cast(float*)buffer_.ptr); 40 case ColumnTypes.MYSQL_TYPE_DOUBLE: 41 return to!string(*cast(double*)buffer_.ptr); 42 case ColumnTypes.MYSQL_TYPE_SET: 43 case ColumnTypes.MYSQL_TYPE_ENUM: 44 case ColumnTypes.MYSQL_TYPE_VARCHAR: 45 case ColumnTypes.MYSQL_TYPE_VAR_STRING: 46 case ColumnTypes.MYSQL_TYPE_STRING: 47 case ColumnTypes.MYSQL_TYPE_NEWDECIMAL: 48 case ColumnTypes.MYSQL_TYPE_DECIMAL: 49 return to!string(*cast(immutable const(char)[]*)buffer_.ptr); 50 case ColumnTypes.MYSQL_TYPE_BIT: 51 case ColumnTypes.MYSQL_TYPE_TINY_BLOB: 52 case ColumnTypes.MYSQL_TYPE_MEDIUM_BLOB: 53 case ColumnTypes.MYSQL_TYPE_LONG_BLOB: 54 case ColumnTypes.MYSQL_TYPE_BLOB: 55 case ColumnTypes.MYSQL_TYPE_GEOMETRY: 56 return to!string(*cast(ubyte[]*)buffer_.ptr); 57 case ColumnTypes.MYSQL_TYPE_TIME: 58 case ColumnTypes.MYSQL_TYPE_TIME2: 59 return (*cast(MySQLTime*)buffer_.ptr).toDuration().toString(); 60 case ColumnTypes.MYSQL_TYPE_DATE: 61 case ColumnTypes.MYSQL_TYPE_NEWDATE: 62 case ColumnTypes.MYSQL_TYPE_DATETIME: 63 case ColumnTypes.MYSQL_TYPE_DATETIME2: 64 case ColumnTypes.MYSQL_TYPE_TIMESTAMP: 65 case ColumnTypes.MYSQL_TYPE_TIMESTAMP2: 66 return (*cast(MySQLDateTime*)buffer_.ptr).to!DateTime().toString(); 67 } 68 } 69 70 T get(T)() const if (isScalarType!T) { 71 final switch(type_) { 72 case ColumnTypes.MYSQL_TYPE_NULL: 73 throw new MySQLErrorException("Cannot convert NULL to scalar"); 74 case ColumnTypes.MYSQL_TYPE_TINY: 75 return cast(T)(*cast(ubyte*)buffer_.ptr); 76 case ColumnTypes.MYSQL_TYPE_YEAR: 77 case ColumnTypes.MYSQL_TYPE_SHORT: 78 return cast(T)(*cast(ushort*)buffer_.ptr); 79 case ColumnTypes.MYSQL_TYPE_INT24: 80 case ColumnTypes.MYSQL_TYPE_LONG: 81 return cast(T)(*cast(uint*)buffer_.ptr); 82 case ColumnTypes.MYSQL_TYPE_LONGLONG: 83 return cast(T)(*cast(ulong*)buffer_.ptr); 84 case ColumnTypes.MYSQL_TYPE_FLOAT: 85 return cast(T)(*cast(float*)buffer_.ptr); 86 case ColumnTypes.MYSQL_TYPE_DOUBLE: 87 return cast(T)(*cast(double*)buffer_.ptr); 88 case ColumnTypes.MYSQL_TYPE_SET: 89 case ColumnTypes.MYSQL_TYPE_ENUM: 90 case ColumnTypes.MYSQL_TYPE_VARCHAR: 91 case ColumnTypes.MYSQL_TYPE_VAR_STRING: 92 case ColumnTypes.MYSQL_TYPE_STRING: 93 case ColumnTypes.MYSQL_TYPE_NEWDECIMAL: 94 case ColumnTypes.MYSQL_TYPE_DECIMAL: 95 break; 96 case ColumnTypes.MYSQL_TYPE_BIT: 97 case ColumnTypes.MYSQL_TYPE_TINY_BLOB: 98 case ColumnTypes.MYSQL_TYPE_MEDIUM_BLOB: 99 case ColumnTypes.MYSQL_TYPE_LONG_BLOB: 100 case ColumnTypes.MYSQL_TYPE_BLOB: 101 case ColumnTypes.MYSQL_TYPE_GEOMETRY: 102 break; 103 case ColumnTypes.MYSQL_TYPE_TIME: 104 case ColumnTypes.MYSQL_TYPE_TIME2: 105 break; 106 case ColumnTypes.MYSQL_TYPE_DATE: 107 case ColumnTypes.MYSQL_TYPE_NEWDATE: 108 case ColumnTypes.MYSQL_TYPE_DATETIME: 109 case ColumnTypes.MYSQL_TYPE_DATETIME2: 110 case ColumnTypes.MYSQL_TYPE_TIMESTAMP: 111 case ColumnTypes.MYSQL_TYPE_TIMESTAMP2: 112 break; 113 } 114 115 throw new MySQLErrorException("Cannot convert MySQL value to scalar"); 116 } 117 118 T get(T)() const if (is(T == SysTime) || is(T == DateTime) || is(T == Date) || is(T == TimeOfDay)) { 119 final switch(type_) { 120 case ColumnTypes.MYSQL_TYPE_NULL: 121 throw new MySQLErrorException("Cannot convert NULL to timestamp"); 122 case ColumnTypes.MYSQL_TYPE_TINY: 123 break; 124 case ColumnTypes.MYSQL_TYPE_YEAR: 125 break; 126 case ColumnTypes.MYSQL_TYPE_SHORT: 127 break; 128 case ColumnTypes.MYSQL_TYPE_INT24: 129 case ColumnTypes.MYSQL_TYPE_LONG: 130 break; 131 case ColumnTypes.MYSQL_TYPE_LONGLONG: 132 break; 133 case ColumnTypes.MYSQL_TYPE_FLOAT: 134 break; 135 case ColumnTypes.MYSQL_TYPE_DOUBLE: 136 break; 137 case ColumnTypes.MYSQL_TYPE_SET: 138 case ColumnTypes.MYSQL_TYPE_ENUM: 139 case ColumnTypes.MYSQL_TYPE_VARCHAR: 140 case ColumnTypes.MYSQL_TYPE_VAR_STRING: 141 case ColumnTypes.MYSQL_TYPE_STRING: 142 case ColumnTypes.MYSQL_TYPE_NEWDECIMAL: 143 case ColumnTypes.MYSQL_TYPE_DECIMAL: 144 break; 145 case ColumnTypes.MYSQL_TYPE_BIT: 146 case ColumnTypes.MYSQL_TYPE_TINY_BLOB: 147 case ColumnTypes.MYSQL_TYPE_MEDIUM_BLOB: 148 case ColumnTypes.MYSQL_TYPE_LONG_BLOB: 149 case ColumnTypes.MYSQL_TYPE_BLOB: 150 case ColumnTypes.MYSQL_TYPE_GEOMETRY: 151 break; 152 case ColumnTypes.MYSQL_TYPE_TIME: 153 case ColumnTypes.MYSQL_TYPE_TIME2: 154 break; 155 case ColumnTypes.MYSQL_TYPE_DATE: 156 case ColumnTypes.MYSQL_TYPE_NEWDATE: 157 case ColumnTypes.MYSQL_TYPE_DATETIME: 158 case ColumnTypes.MYSQL_TYPE_DATETIME2: 159 case ColumnTypes.MYSQL_TYPE_TIMESTAMP: 160 case ColumnTypes.MYSQL_TYPE_TIMESTAMP2: 161 return (*cast(MySQLDateTime*)buffer_.ptr).to!T; 162 } 163 164 throw new MySQLErrorException("Cannot convert MySQL value to timestamp"); 165 } 166 167 T get(T)() const if (is(T == Duration)) { 168 final switch(type_) { 169 case ColumnTypes.MYSQL_TYPE_NULL: 170 throw new MySQLErrorException("Cannot convert NULL to time"); 171 case ColumnTypes.MYSQL_TYPE_TINY: 172 break; 173 case ColumnTypes.MYSQL_TYPE_YEAR: 174 break; 175 case ColumnTypes.MYSQL_TYPE_SHORT: 176 break; 177 case ColumnTypes.MYSQL_TYPE_INT24: 178 case ColumnTypes.MYSQL_TYPE_LONG: 179 break; 180 case ColumnTypes.MYSQL_TYPE_LONGLONG: 181 break; 182 case ColumnTypes.MYSQL_TYPE_FLOAT: 183 break; 184 case ColumnTypes.MYSQL_TYPE_DOUBLE: 185 break; 186 case ColumnTypes.MYSQL_TYPE_SET: 187 case ColumnTypes.MYSQL_TYPE_ENUM: 188 case ColumnTypes.MYSQL_TYPE_VARCHAR: 189 case ColumnTypes.MYSQL_TYPE_VAR_STRING: 190 case ColumnTypes.MYSQL_TYPE_STRING: 191 case ColumnTypes.MYSQL_TYPE_NEWDECIMAL: 192 case ColumnTypes.MYSQL_TYPE_DECIMAL: 193 break; 194 case ColumnTypes.MYSQL_TYPE_BIT: 195 case ColumnTypes.MYSQL_TYPE_TINY_BLOB: 196 case ColumnTypes.MYSQL_TYPE_MEDIUM_BLOB: 197 case ColumnTypes.MYSQL_TYPE_LONG_BLOB: 198 case ColumnTypes.MYSQL_TYPE_BLOB: 199 case ColumnTypes.MYSQL_TYPE_GEOMETRY: 200 break; 201 case ColumnTypes.MYSQL_TYPE_TIME: 202 case ColumnTypes.MYSQL_TYPE_TIME2: 203 return (*cast(MySQLTime*)buffer_.ptr).toDuration; 204 case ColumnTypes.MYSQL_TYPE_DATE: 205 case ColumnTypes.MYSQL_TYPE_NEWDATE: 206 case ColumnTypes.MYSQL_TYPE_DATETIME: 207 case ColumnTypes.MYSQL_TYPE_DATETIME2: 208 case ColumnTypes.MYSQL_TYPE_TIMESTAMP: 209 case ColumnTypes.MYSQL_TYPE_TIMESTAMP2: 210 break; 211 } 212 213 throw new MySQLErrorException("Cannot convert MySQL value to time"); 214 } 215 216 T get(T)() const if (isArray!T) { 217 final switch(type_) { 218 case ColumnTypes.MYSQL_TYPE_NULL: 219 throw new MySQLErrorException("Cannot convert NULL to array"); 220 case ColumnTypes.MYSQL_TYPE_TINY: 221 break; 222 case ColumnTypes.MYSQL_TYPE_YEAR: 223 break; 224 case ColumnTypes.MYSQL_TYPE_SHORT: 225 break; 226 case ColumnTypes.MYSQL_TYPE_INT24: 227 case ColumnTypes.MYSQL_TYPE_LONG: 228 break; 229 case ColumnTypes.MYSQL_TYPE_LONGLONG: 230 break; 231 case ColumnTypes.MYSQL_TYPE_FLOAT: 232 break; 233 case ColumnTypes.MYSQL_TYPE_DOUBLE: 234 break; 235 case ColumnTypes.MYSQL_TYPE_SET: 236 case ColumnTypes.MYSQL_TYPE_ENUM: 237 case ColumnTypes.MYSQL_TYPE_VARCHAR: 238 case ColumnTypes.MYSQL_TYPE_VAR_STRING: 239 case ColumnTypes.MYSQL_TYPE_STRING: 240 case ColumnTypes.MYSQL_TYPE_NEWDECIMAL: 241 case ColumnTypes.MYSQL_TYPE_DECIMAL: 242 return *cast(T*)buffer_.ptr; 243 case ColumnTypes.MYSQL_TYPE_BIT: 244 case ColumnTypes.MYSQL_TYPE_TINY_BLOB: 245 case ColumnTypes.MYSQL_TYPE_MEDIUM_BLOB: 246 case ColumnTypes.MYSQL_TYPE_LONG_BLOB: 247 case ColumnTypes.MYSQL_TYPE_BLOB: 248 case ColumnTypes.MYSQL_TYPE_GEOMETRY: 249 return *cast(T*)buffer_.ptr; 250 case ColumnTypes.MYSQL_TYPE_TIME: 251 case ColumnTypes.MYSQL_TYPE_TIME2: 252 break; 253 case ColumnTypes.MYSQL_TYPE_DATE: 254 case ColumnTypes.MYSQL_TYPE_NEWDATE: 255 case ColumnTypes.MYSQL_TYPE_DATETIME: 256 case ColumnTypes.MYSQL_TYPE_DATETIME2: 257 case ColumnTypes.MYSQL_TYPE_TIMESTAMP: 258 case ColumnTypes.MYSQL_TYPE_TIMESTAMP2: 259 break; 260 } 261 262 throw new MySQLErrorException("Cannot convert MySQL value to array"); 263 } 264 265 bool isNull() const { 266 return type_ == ColumnTypes.MYSQL_TYPE_NULL; 267 } 268 269 ColumnTypes type() const { 270 return type_; 271 } 272 273 package void nullify() { 274 type_ = ColumnTypes.MYSQL_TYPE_NULL; 275 } 276 277 private: 278 ColumnTypes type_ = ColumnTypes.MYSQL_TYPE_NULL; 279 ubyte[BufferSize] buffer_; 280 } 281 282 283 struct MySQLColumn { 284 uint length; 285 ushort flags; 286 ubyte decimals; 287 ColumnTypes type; 288 string name; // todo: fix allocation 289 } 290 291 292 alias MySQLHeader = MySQLColumn[]; 293 alias MySQLRow = MySQLValue[]; 294 295 296 struct MySQLTime { 297 uint days; 298 ubyte negative; 299 ubyte hours; 300 ubyte mins; 301 ubyte secs; 302 uint usecs; 303 304 Duration toDuration() { 305 auto total = days * 86400_000_000L + 306 hours * 3600_000_000L + 307 mins * 60_000_000L + 308 secs * 1_000_000L + 309 usecs; 310 return dur!"usecs"(negative ? -total : total); 311 } 312 313 static MySQLTime from(Duration duration) { 314 MySQLTime time; 315 duration.abs.split!("days", "hours", "minutes", "seconds", "usecs")(time.days, time.hours, time.mins, time.secs, time.usecs); 316 time.negative = duration.isNegative ? 1 : 0; 317 return time; 318 } 319 } 320 321 void putMySQLTime(ref OutputPacket packet, in MySQLTime time) { 322 if (time.days || time.hours || time.mins || time.mins || time.usecs) { 323 auto usecs = time.usecs != 0; 324 packet.put!ubyte(usecs ? 12 : 8); 325 packet.put!ubyte(time.negative); 326 packet.put!uint(time.days); 327 packet.put!ubyte(time.hours); 328 packet.put!ubyte(time.mins); 329 packet.put!ubyte(time.secs); 330 if (usecs) 331 packet.put!uint(time.usecs); 332 } else { 333 packet.put!ubyte(0); 334 } 335 } 336 337 auto eatMySQLTime(ref InputPacket packet) { 338 MySQLTime time; 339 switch(packet.eat!ubyte) { 340 case 12: 341 time.negative = packet.eat!ubyte; 342 time.days = packet.eat!uint; 343 time.hours = packet.eat!ubyte; 344 time.mins = packet.eat!ubyte; 345 time.secs = packet.eat!ubyte; 346 time.usecs = packet.eat!uint; 347 break; 348 case 8: 349 time.negative = packet.eat!ubyte; 350 time.days = packet.eat!uint; 351 time.hours = packet.eat!ubyte; 352 time.mins = packet.eat!ubyte; 353 time.secs = packet.eat!ubyte; 354 break; 355 case 0: 356 break; 357 default: 358 throw new MySQLProtocolException("Bad time struct format"); 359 } 360 361 return time; 362 } 363 364 365 struct MySQLDateTime { 366 ushort year = 0; 367 ubyte month = 0; 368 ubyte day = 0; 369 ubyte hour = 0; 370 ubyte min = 0; 371 ubyte sec = 0; 372 uint usec = 0; 373 374 bool valid() const { 375 return month != 0; 376 } 377 378 T to(T)() if (is(T == SysTime)) { 379 return SysTime(DateTime(year, month, day, hour, min, sec), FracSec.from!"usecs"(usec), UTC()); 380 } 381 382 T to(T)() if (is(T == DateTime)) { 383 return DateTime(year, month, day, hour, min, sec); 384 } 385 386 T to(T)() if (is(T == Date)) { 387 return Date(year, month, day); 388 } 389 390 T to(T)() if (is(T == TimeOfDay)) { 391 return TimeOfDay(hour, min, sec); 392 } 393 394 static MySQLDateTime from(SysTime sysTime) { 395 MySQLDateTime time; 396 397 auto dateTime = cast(DateTime)sysTime; 398 time.year = dateTime.year; 399 time.month = dateTime.month; 400 time.day = dateTime.day; 401 time.hour = dateTime.hour; 402 time.min = dateTime.minute; 403 time.sec = dateTime.second; 404 time.usec = sysTime.fracSec.usecs; 405 406 return time; 407 } 408 409 static MySQLDateTime from(DateTime dateTime) { 410 MySQLDateTime time; 411 412 time.year = dateTime.year; 413 time.month = dateTime.month; 414 time.day = dateTime.day; 415 time.hour = dateTime.hour; 416 time.min = dateTime.minute; 417 time.sec = dateTime.second; 418 419 return time; 420 } 421 422 static MySQLDateTime from(Date date) { 423 MySQLDateTime time; 424 425 time.year = date.year; 426 time.month = date.month; 427 time.day = date.day; 428 429 return time; 430 } 431 } 432 433 void putMySQLDateTime(ref OutputPacket packet, in MySQLDateTime time) { 434 auto marker = packet.marker!ubyte; 435 ubyte length = 0; 436 437 if (time.year || time.month || time.day) { 438 length = 4; 439 packet.put!ushort(time.year); 440 packet.put!ubyte(time.month); 441 packet.put!ubyte(time.day); 442 443 if (time.hour || time.min || time.sec || time.usec) { 444 length = 7; 445 packet.put!ubyte(time.hour); 446 packet.put!ubyte(time.min); 447 packet.put!ubyte(time.sec); 448 449 if (time.usec) { 450 length = 11; 451 packet.put!uint(time.usec); 452 } 453 } 454 } 455 456 packet.put!ubyte(marker, length); 457 } 458 459 auto eatMySQLDateTime(ref InputPacket packet) { 460 MySQLDateTime time; 461 switch(packet.eat!ubyte) { 462 case 11: 463 time.year = packet.eat!ushort; 464 time.month = packet.eat!ubyte; 465 time.day = packet.eat!ubyte; 466 time.hour = packet.eat!ubyte; 467 time.min = packet.eat!ubyte; 468 time.sec = packet.eat!ubyte; 469 time.usec = packet.eat!uint; 470 break; 471 case 7: 472 time.year = packet.eat!ushort; 473 time.month = packet.eat!ubyte; 474 time.day = packet.eat!ubyte; 475 time.hour = packet.eat!ubyte; 476 time.min = packet.eat!ubyte; 477 time.sec = packet.eat!ubyte; 478 break; 479 case 4: 480 time.year = packet.eat!ushort; 481 time.month = packet.eat!ubyte; 482 time.day = packet.eat!ubyte; 483 break; 484 case 0: 485 break; 486 default: 487 throw new MySQLProtocolException("Bad datetime struct format"); 488 } 489 490 return time; 491 } 492 493 494 MySQLValue eatValue(ref InputPacket packet, in MySQLColumn column) { 495 MySQLValue value; 496 497 final switch(column.type) { 498 case ColumnTypes.MYSQL_TYPE_NULL: 499 value = MySQLValue(column.type, null, 0); 500 break; 501 case ColumnTypes.MYSQL_TYPE_TINY: 502 auto x = packet.eat!ubyte; 503 value = MySQLValue(column.type, &x, 1); 504 break; 505 case ColumnTypes.MYSQL_TYPE_YEAR: 506 case ColumnTypes.MYSQL_TYPE_SHORT: 507 auto x = packet.eat!ushort; 508 value = MySQLValue(column.type, &x, 2); 509 break; 510 case ColumnTypes.MYSQL_TYPE_INT24: 511 case ColumnTypes.MYSQL_TYPE_LONG: 512 auto x = packet.eat!uint; 513 value = MySQLValue(column.type, &x, 4); 514 break; 515 case ColumnTypes.MYSQL_TYPE_DOUBLE: 516 case ColumnTypes.MYSQL_TYPE_LONGLONG: 517 auto x = packet.eat!ulong; 518 value = MySQLValue(column.type, &x, 8); 519 break; 520 case ColumnTypes.MYSQL_TYPE_FLOAT: 521 auto x = packet.eat!float; 522 value = MySQLValue(column.type, &x, 4); 523 break; 524 case ColumnTypes.MYSQL_TYPE_SET: 525 case ColumnTypes.MYSQL_TYPE_ENUM: 526 case ColumnTypes.MYSQL_TYPE_VARCHAR: 527 case ColumnTypes.MYSQL_TYPE_VAR_STRING: 528 case ColumnTypes.MYSQL_TYPE_STRING: 529 case ColumnTypes.MYSQL_TYPE_NEWDECIMAL: 530 case ColumnTypes.MYSQL_TYPE_DECIMAL: 531 auto x = packet.eat!(const(char)[])(cast(size_t)packet.eatLenEnc()); 532 value = MySQLValue(column.type, &x, typeof(x).sizeof); 533 break; 534 case ColumnTypes.MYSQL_TYPE_BIT: 535 case ColumnTypes.MYSQL_TYPE_TINY_BLOB: 536 case ColumnTypes.MYSQL_TYPE_MEDIUM_BLOB: 537 case ColumnTypes.MYSQL_TYPE_LONG_BLOB: 538 case ColumnTypes.MYSQL_TYPE_BLOB: 539 case ColumnTypes.MYSQL_TYPE_GEOMETRY: 540 auto x = packet.eat!(const(ubyte)[])(cast(size_t)packet.eatLenEnc()); 541 value = MySQLValue(column.type, &x, typeof(x).sizeof); 542 break; 543 case ColumnTypes.MYSQL_TYPE_TIME: 544 case ColumnTypes.MYSQL_TYPE_TIME2: 545 auto x = eatMySQLTime(packet); 546 value = MySQLValue(column.type, &x, typeof(x).sizeof); 547 break; 548 case ColumnTypes.MYSQL_TYPE_DATE: 549 case ColumnTypes.MYSQL_TYPE_NEWDATE: 550 case ColumnTypes.MYSQL_TYPE_DATETIME: 551 case ColumnTypes.MYSQL_TYPE_DATETIME2: 552 case ColumnTypes.MYSQL_TYPE_TIMESTAMP: 553 case ColumnTypes.MYSQL_TYPE_TIMESTAMP2: 554 auto x = eatMySQLDateTime(packet); 555 if (x.valid()) 556 value = MySQLValue(column.type, &x, typeof(x).sizeof); 557 else 558 value = MySQLValue(ColumnTypes.MYSQL_TYPE_NULL, null, 0); 559 break; 560 } 561 562 return value; 563 } 564 565 void putValueType(T)(ref OutputPacket packet, T value) if (is(T == Date) || is(T == DateTime) || is(T == SysTime)) { 566 packet.put!ubyte(ColumnTypes.MYSQL_TYPE_TIMESTAMP); 567 packet.put!ubyte(0x80); 568 } 569 570 void putValue(T)(ref OutputPacket packet, T value) if (is(T == Date) || is(T == DateTime) || is(T == SysTime)) { 571 putMySQLDateTime(packet, MySQLDateTime.from(value)); 572 } 573 574 void putValueType(T)(ref OutputPacket packet, T value) if (is(T == Duration)) { 575 packet.put!ubyte(ColumnTypes.MYSQL_TYPE_TIME); 576 packet.put!ubyte(0x00); 577 } 578 579 void putValue(T)(ref OutputPacket packet, T value) if (is(T == Duration)) { 580 putMySQLTime(packet, MySQLTime.from(value)); 581 } 582 583 void putValueType(T)(ref OutputPacket packet, T value) if (isIntegral!T || isBoolean!T) { 584 static if (isUnsigned!T) { 585 const ubyte signbyte = 0x80; 586 } else { 587 const ubyte signbyte = 0x00; 588 } 589 590 alias TS = SignedTypeOf!T; 591 592 static if (is(T == long)) { 593 packet.put!ubyte(ColumnTypes.MYSQL_TYPE_LONGLONG); 594 packet.put!ubyte(signbyte); 595 } else static if (is(T == int) || is(T == dchar)) { 596 packet.put!ubyte(ColumnTypes.MYSQL_TYPE_LONG); 597 packet.put!ubyte(signbyte); 598 } else static if (is(T == short) || is(T == wchar)) { 599 packet.put!ubyte(ColumnTypes.MYSQL_TYPE_SHORT); 600 packet.put!ubyte(signbyte); 601 } else static if (is(T == byte) || is(T == char) || is(T == bool)) { 602 packet.put!ubyte(ColumnTypes.MYSQL_TYPE_TINY); 603 packet.put!ubyte(signbyte); 604 } 605 } 606 607 void putValueType(T)(ref OutputPacket packet, T value) if (is(T == typeof(null))) { 608 packet.put!ubyte(ColumnTypes.MYSQL_TYPE_NULL); 609 packet.put!ubyte(0x00); 610 } 611 612 void putValue(T)(ref OutputPacket packet, T value) if (isIntegral!T || isBoolean!T) { 613 alias TS = SignedTypeOf!T; 614 615 static if (is(T == long)) { 616 packet.put!ulong(value); 617 } else static if (is(T == int) || is(T == dchar)) { 618 packet.put!uint(value); 619 } else static if (is(T == short) || is(T == wchar)) { 620 packet.put!ushort(value); 621 } else static if (is(T == byte) || is(T == char) || is(T == bool)) { 622 packet.put!ushort(value); 623 } 624 } 625 626 void putValueType(T)(ref OutputPacket packet, T value) if (isArray!T) { 627 alias ValueType = Unqual!(typeof(T.init[0])); 628 static if (isSomeChar!ValueType) { 629 packet.put!ubyte(ColumnTypes.MYSQL_TYPE_STRING); 630 } else { 631 packet.put!ubyte(ColumnTypes.MYSQL_TYPE_BLOB); 632 } 633 packet.put!ubyte(0x80); 634 } 635 636 void putValue(T)(ref OutputPacket packet, T value) if (isArray!T) { 637 alias ValueType = Unqual!(typeof(T.init[0])); 638 639 ulong size = value.length * ValueType.sizeof; 640 packet.putLenEnc(size); 641 packet.put(value); 642 }