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