1package mssql 2 3import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "io" 8 "math" 9 "reflect" 10 "strconv" 11 "time" 12 13 "github.com/denisenkom/go-mssqldb/internal/cp" 14 "github.com/denisenkom/go-mssqldb/internal/decimal" 15) 16 17// fixed-length data types 18// http://msdn.microsoft.com/en-us/library/dd341171.aspx 19const ( 20 typeNull = 0x1f 21 typeInt1 = 0x30 22 typeBit = 0x32 23 typeInt2 = 0x34 24 typeInt4 = 0x38 25 typeDateTim4 = 0x3a 26 typeFlt4 = 0x3b 27 typeMoney = 0x3c 28 typeDateTime = 0x3d 29 typeFlt8 = 0x3e 30 typeMoney4 = 0x7a 31 typeInt8 = 0x7f 32) 33 34// variable-length data types 35// http://msdn.microsoft.com/en-us/library/dd358341.aspx 36const ( 37 // byte len types 38 typeGuid = 0x24 39 typeIntN = 0x26 40 typeDecimal = 0x37 // legacy 41 typeNumeric = 0x3f // legacy 42 typeBitN = 0x68 43 typeDecimalN = 0x6a 44 typeNumericN = 0x6c 45 typeFltN = 0x6d 46 typeMoneyN = 0x6e 47 typeDateTimeN = 0x6f 48 typeDateN = 0x28 49 typeTimeN = 0x29 50 typeDateTime2N = 0x2a 51 typeDateTimeOffsetN = 0x2b 52 typeChar = 0x2f // legacy 53 typeVarChar = 0x27 // legacy 54 typeBinary = 0x2d // legacy 55 typeVarBinary = 0x25 // legacy 56 57 // short length types 58 typeBigVarBin = 0xa5 59 typeBigVarChar = 0xa7 60 typeBigBinary = 0xad 61 typeBigChar = 0xaf 62 typeNVarChar = 0xe7 63 typeNChar = 0xef 64 typeXml = 0xf1 65 typeUdt = 0xf0 66 typeTvp = 0xf3 67 68 // long length types 69 typeText = 0x23 70 typeImage = 0x22 71 typeNText = 0x63 72 typeVariant = 0x62 73) 74const _PLP_NULL = 0xFFFFFFFFFFFFFFFF 75const _UNKNOWN_PLP_LEN = 0xFFFFFFFFFFFFFFFE 76const _PLP_TERMINATOR = 0x00000000 77 78// TVP COLUMN FLAGS 79const _TVP_END_TOKEN = 0x00 80const _TVP_ROW_TOKEN = 0x01 81 82// TYPE_INFO rule 83// http://msdn.microsoft.com/en-us/library/dd358284.aspx 84type typeInfo struct { 85 TypeId uint8 86 Size int 87 Scale uint8 88 Prec uint8 89 Buffer []byte 90 Collation cp.Collation 91 UdtInfo udtInfo 92 XmlInfo xmlInfo 93 Reader func(ti *typeInfo, r *tdsBuffer) (res interface{}) 94 Writer func(w io.Writer, ti typeInfo, buf []byte) (err error) 95} 96 97// Common Language Runtime (CLR) Instances 98// http://msdn.microsoft.com/en-us/library/dd357962.aspx 99type udtInfo struct { 100 //MaxByteSize uint32 101 DBName string 102 SchemaName string 103 TypeName string 104 AssemblyQualifiedName string 105} 106 107// XML Values 108// http://msdn.microsoft.com/en-us/library/dd304764.aspx 109type xmlInfo struct { 110 SchemaPresent uint8 111 DBName string 112 OwningSchema string 113 XmlSchemaCollection string 114} 115 116func readTypeInfo(r *tdsBuffer) (res typeInfo) { 117 res.TypeId = r.byte() 118 switch res.TypeId { 119 case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4, 120 typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8: 121 // those are fixed length types 122 switch res.TypeId { 123 case typeNull: 124 res.Size = 0 125 case typeInt1, typeBit: 126 res.Size = 1 127 case typeInt2: 128 res.Size = 2 129 case typeInt4, typeDateTim4, typeFlt4, typeMoney4: 130 res.Size = 4 131 case typeMoney, typeDateTime, typeFlt8, typeInt8: 132 res.Size = 8 133 } 134 res.Reader = readFixedType 135 res.Buffer = make([]byte, res.Size) 136 default: // all others are VARLENTYPE 137 readVarLen(&res, r) 138 } 139 return 140} 141 142// https://msdn.microsoft.com/en-us/library/dd358284.aspx 143func writeTypeInfo(w io.Writer, ti *typeInfo) (err error) { 144 err = binary.Write(w, binary.LittleEndian, ti.TypeId) 145 if err != nil { 146 return 147 } 148 switch ti.TypeId { 149 case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4, 150 typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8: 151 // those are fixed length 152 // https://msdn.microsoft.com/en-us/library/dd341171.aspx 153 ti.Writer = writeFixedType 154 case typeTvp: 155 ti.Writer = writeFixedType 156 default: // all others are VARLENTYPE 157 err = writeVarLen(w, ti) 158 if err != nil { 159 return 160 } 161 } 162 return 163} 164 165func writeFixedType(w io.Writer, ti typeInfo, buf []byte) (err error) { 166 _, err = w.Write(buf) 167 return 168} 169 170// https://msdn.microsoft.com/en-us/library/dd358341.aspx 171func writeVarLen(w io.Writer, ti *typeInfo) (err error) { 172 switch ti.TypeId { 173 174 case typeDateN: 175 ti.Writer = writeByteLenType 176 case typeTimeN, typeDateTime2N, typeDateTimeOffsetN: 177 if err = binary.Write(w, binary.LittleEndian, ti.Scale); err != nil { 178 return 179 } 180 ti.Writer = writeByteLenType 181 case typeIntN, typeDecimal, typeNumeric, 182 typeBitN, typeDecimalN, typeNumericN, typeFltN, 183 typeMoneyN, typeDateTimeN, typeChar, 184 typeVarChar, typeBinary, typeVarBinary: 185 186 // byle len types 187 if ti.Size > 0xff { 188 panic("Invalid size for BYLELEN_TYPE") 189 } 190 if err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)); err != nil { 191 return 192 } 193 switch ti.TypeId { 194 case typeDecimal, typeNumeric, typeDecimalN, typeNumericN: 195 err = binary.Write(w, binary.LittleEndian, ti.Prec) 196 if err != nil { 197 return 198 } 199 err = binary.Write(w, binary.LittleEndian, ti.Scale) 200 if err != nil { 201 return 202 } 203 } 204 ti.Writer = writeByteLenType 205 case typeGuid: 206 if !(ti.Size == 0x10 || ti.Size == 0x00) { 207 panic("Invalid size for BYLELEN_TYPE") 208 } 209 if err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)); err != nil { 210 return 211 } 212 ti.Writer = writeByteLenType 213 case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar, 214 typeNVarChar, typeNChar, typeXml, typeUdt: 215 216 // short len types 217 if ti.Size > 8000 || ti.Size == 0 { 218 if err = binary.Write(w, binary.LittleEndian, uint16(0xffff)); err != nil { 219 return 220 } 221 ti.Writer = writePLPType 222 } else { 223 if err = binary.Write(w, binary.LittleEndian, uint16(ti.Size)); err != nil { 224 return 225 } 226 ti.Writer = writeShortLenType 227 } 228 switch ti.TypeId { 229 case typeBigVarChar, typeBigChar, typeNVarChar, typeNChar: 230 if err = writeCollation(w, ti.Collation); err != nil { 231 return 232 } 233 case typeXml: 234 if err = binary.Write(w, binary.LittleEndian, ti.XmlInfo.SchemaPresent); err != nil { 235 return 236 } 237 } 238 case typeText, typeImage, typeNText, typeVariant: 239 // LONGLEN_TYPE 240 if err = binary.Write(w, binary.LittleEndian, uint32(ti.Size)); err != nil { 241 return 242 } 243 if err = writeCollation(w, ti.Collation); err != nil { 244 return 245 } 246 ti.Writer = writeLongLenType 247 default: 248 panic("Invalid type") 249 } 250 return 251} 252 253// http://msdn.microsoft.com/en-us/library/ee780895.aspx 254func decodeDateTim4(buf []byte) time.Time { 255 days := binary.LittleEndian.Uint16(buf) 256 mins := binary.LittleEndian.Uint16(buf[2:]) 257 return time.Date(1900, 1, 1+int(days), 258 0, int(mins), 0, 0, time.UTC) 259} 260 261func encodeDateTim4(val time.Time) (buf []byte) { 262 buf = make([]byte, 4) 263 264 ref := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC) 265 dur := val.Sub(ref) 266 days := dur / (24 * time.Hour) 267 mins := val.Hour()*60 + val.Minute() 268 if days < 0 { 269 days = 0 270 mins = 0 271 } 272 273 binary.LittleEndian.PutUint16(buf[:2], uint16(days)) 274 binary.LittleEndian.PutUint16(buf[2:], uint16(mins)) 275 return 276} 277 278// encodes datetime value 279// type identifier is typeDateTimeN 280func encodeDateTime(t time.Time) (res []byte) { 281 // base date in days since Jan 1st 1900 282 basedays := gregorianDays(1900, 1) 283 // days since Jan 1st 1900 (same TZ as t) 284 days := gregorianDays(t.Year(), t.YearDay()) - basedays 285 tm := 300*(t.Second()+t.Minute()*60+t.Hour()*60*60) + t.Nanosecond()*300/1e9 286 // minimum and maximum possible 287 mindays := gregorianDays(1753, 1) - basedays 288 maxdays := gregorianDays(9999, 365) - basedays 289 if days < mindays { 290 days = mindays 291 tm = 0 292 } 293 if days > maxdays { 294 days = maxdays 295 tm = (23*60*60+59*60+59)*300 + 299 296 } 297 res = make([]byte, 8) 298 binary.LittleEndian.PutUint32(res[0:4], uint32(days)) 299 binary.LittleEndian.PutUint32(res[4:8], uint32(tm)) 300 return 301} 302 303func decodeDateTime(buf []byte) time.Time { 304 days := int32(binary.LittleEndian.Uint32(buf)) 305 tm := binary.LittleEndian.Uint32(buf[4:]) 306 ns := int(math.Trunc(float64(tm%300)/0.3+0.5)) * 1000000 307 secs := int(tm / 300) 308 return time.Date(1900, 1, 1+int(days), 309 0, 0, secs, ns, time.UTC) 310} 311 312func readFixedType(ti *typeInfo, r *tdsBuffer) interface{} { 313 r.ReadFull(ti.Buffer) 314 buf := ti.Buffer 315 switch ti.TypeId { 316 case typeNull: 317 return nil 318 case typeInt1: 319 return int64(buf[0]) 320 case typeBit: 321 return buf[0] != 0 322 case typeInt2: 323 return int64(int16(binary.LittleEndian.Uint16(buf))) 324 case typeInt4: 325 return int64(int32(binary.LittleEndian.Uint32(buf))) 326 case typeDateTim4: 327 return decodeDateTim4(buf) 328 case typeFlt4: 329 return math.Float32frombits(binary.LittleEndian.Uint32(buf)) 330 case typeMoney4: 331 return decodeMoney4(buf) 332 case typeMoney: 333 return decodeMoney(buf) 334 case typeDateTime: 335 return decodeDateTime(buf) 336 case typeFlt8: 337 return math.Float64frombits(binary.LittleEndian.Uint64(buf)) 338 case typeInt8: 339 return int64(binary.LittleEndian.Uint64(buf)) 340 default: 341 badStreamPanicf("Invalid typeid") 342 } 343 panic("shoulnd't get here") 344} 345 346func readByteLenType(ti *typeInfo, r *tdsBuffer) interface{} { 347 size := r.byte() 348 if size == 0 { 349 return nil 350 } 351 r.ReadFull(ti.Buffer[:size]) 352 buf := ti.Buffer[:size] 353 switch ti.TypeId { 354 case typeDateN: 355 if len(buf) != 3 { 356 badStreamPanicf("Invalid size for DATENTYPE") 357 } 358 return decodeDate(buf) 359 case typeTimeN: 360 return decodeTime(ti.Scale, buf) 361 case typeDateTime2N: 362 return decodeDateTime2(ti.Scale, buf) 363 case typeDateTimeOffsetN: 364 return decodeDateTimeOffset(ti.Scale, buf) 365 case typeGuid: 366 return decodeGuid(buf) 367 case typeIntN: 368 switch len(buf) { 369 case 1: 370 return int64(buf[0]) 371 case 2: 372 return int64(int16((binary.LittleEndian.Uint16(buf)))) 373 case 4: 374 return int64(int32(binary.LittleEndian.Uint32(buf))) 375 case 8: 376 return int64(binary.LittleEndian.Uint64(buf)) 377 default: 378 badStreamPanicf("Invalid size for INTNTYPE: %d", len(buf)) 379 } 380 case typeDecimal, typeNumeric, typeDecimalN, typeNumericN: 381 return decodeDecimal(ti.Prec, ti.Scale, buf) 382 case typeBitN: 383 if len(buf) != 1 { 384 badStreamPanicf("Invalid size for BITNTYPE") 385 } 386 return buf[0] != 0 387 case typeFltN: 388 switch len(buf) { 389 case 4: 390 return float64(math.Float32frombits(binary.LittleEndian.Uint32(buf))) 391 case 8: 392 return math.Float64frombits(binary.LittleEndian.Uint64(buf)) 393 default: 394 badStreamPanicf("Invalid size for FLTNTYPE") 395 } 396 case typeMoneyN: 397 switch len(buf) { 398 case 4: 399 return decodeMoney4(buf) 400 case 8: 401 return decodeMoney(buf) 402 default: 403 badStreamPanicf("Invalid size for MONEYNTYPE") 404 } 405 case typeDateTim4: 406 return decodeDateTim4(buf) 407 case typeDateTime: 408 return decodeDateTime(buf) 409 case typeDateTimeN: 410 switch len(buf) { 411 case 4: 412 return decodeDateTim4(buf) 413 case 8: 414 return decodeDateTime(buf) 415 default: 416 badStreamPanicf("Invalid size for DATETIMENTYPE") 417 } 418 case typeChar, typeVarChar: 419 return decodeChar(ti.Collation, buf) 420 case typeBinary, typeVarBinary: 421 // a copy, because the backing array for ti.Buffer is reused 422 // and can be overwritten by the next row while this row waits 423 // in a buffered chan 424 cpy := make([]byte, len(buf)) 425 copy(cpy, buf) 426 return cpy 427 default: 428 badStreamPanicf("Invalid typeid") 429 } 430 panic("shoulnd't get here") 431} 432 433func writeByteLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { 434 if ti.Size > 0xff { 435 panic("Invalid size for BYTELEN_TYPE") 436 } 437 err = binary.Write(w, binary.LittleEndian, uint8(len(buf))) 438 if err != nil { 439 return 440 } 441 _, err = w.Write(buf) 442 return 443} 444 445func readShortLenType(ti *typeInfo, r *tdsBuffer) interface{} { 446 size := r.uint16() 447 if size == 0xffff { 448 return nil 449 } 450 r.ReadFull(ti.Buffer[:size]) 451 buf := ti.Buffer[:size] 452 switch ti.TypeId { 453 case typeBigVarChar, typeBigChar: 454 return decodeChar(ti.Collation, buf) 455 case typeBigVarBin, typeBigBinary: 456 // a copy, because the backing array for ti.Buffer is reused 457 // and can be overwritten by the next row while this row waits 458 // in a buffered chan 459 cpy := make([]byte, len(buf)) 460 copy(cpy, buf) 461 return cpy 462 case typeNVarChar, typeNChar: 463 return decodeNChar(buf) 464 case typeUdt: 465 return decodeUdt(*ti, buf) 466 default: 467 badStreamPanicf("Invalid typeid") 468 } 469 panic("shoulnd't get here") 470} 471 472func writeShortLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { 473 if buf == nil { 474 err = binary.Write(w, binary.LittleEndian, uint16(0xffff)) 475 return 476 } 477 if ti.Size > 0xfffe { 478 panic("Invalid size for USHORTLEN_TYPE") 479 } 480 err = binary.Write(w, binary.LittleEndian, uint16(ti.Size)) 481 if err != nil { 482 return 483 } 484 _, err = w.Write(buf) 485 return 486} 487 488func readLongLenType(ti *typeInfo, r *tdsBuffer) interface{} { 489 // information about this format can be found here: 490 // http://msdn.microsoft.com/en-us/library/dd304783.aspx 491 // and here: 492 // http://msdn.microsoft.com/en-us/library/dd357254.aspx 493 textptrsize := int(r.byte()) 494 if textptrsize == 0 { 495 return nil 496 } 497 textptr := make([]byte, textptrsize) 498 r.ReadFull(textptr) 499 timestamp := r.uint64() 500 _ = timestamp // ignore timestamp 501 size := r.int32() 502 if size == -1 { 503 return nil 504 } 505 buf := make([]byte, size) 506 r.ReadFull(buf) 507 switch ti.TypeId { 508 case typeText: 509 return decodeChar(ti.Collation, buf) 510 case typeImage: 511 return buf 512 case typeNText: 513 return decodeNChar(buf) 514 default: 515 badStreamPanicf("Invalid typeid") 516 } 517 panic("shoulnd't get here") 518} 519func writeLongLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { 520 //textptr 521 err = binary.Write(w, binary.LittleEndian, byte(0x10)) 522 if err != nil { 523 return 524 } 525 err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) 526 if err != nil { 527 return 528 } 529 err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) 530 if err != nil { 531 return 532 } 533 //timestamp? 534 err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) 535 if err != nil { 536 return 537 } 538 539 err = binary.Write(w, binary.LittleEndian, uint32(ti.Size)) 540 if err != nil { 541 return 542 } 543 _, err = w.Write(buf) 544 return 545} 546 547func readCollation(r *tdsBuffer) (res cp.Collation) { 548 res.LcidAndFlags = r.uint32() 549 res.SortId = r.byte() 550 return 551} 552 553func writeCollation(w io.Writer, col cp.Collation) (err error) { 554 if err = binary.Write(w, binary.LittleEndian, col.LcidAndFlags); err != nil { 555 return 556 } 557 err = binary.Write(w, binary.LittleEndian, col.SortId) 558 return 559} 560 561// reads variant value 562// http://msdn.microsoft.com/en-us/library/dd303302.aspx 563func readVariantType(ti *typeInfo, r *tdsBuffer) interface{} { 564 size := r.int32() 565 if size == 0 { 566 return nil 567 } 568 vartype := r.byte() 569 propbytes := int32(r.byte()) 570 switch vartype { 571 case typeGuid: 572 buf := make([]byte, size-2-propbytes) 573 r.ReadFull(buf) 574 return buf 575 case typeBit: 576 return r.byte() != 0 577 case typeInt1: 578 return int64(r.byte()) 579 case typeInt2: 580 return int64(int16(r.uint16())) 581 case typeInt4: 582 return int64(r.int32()) 583 case typeInt8: 584 return int64(r.uint64()) 585 case typeDateTime: 586 buf := make([]byte, size-2-propbytes) 587 r.ReadFull(buf) 588 return decodeDateTime(buf) 589 case typeDateTim4: 590 buf := make([]byte, size-2-propbytes) 591 r.ReadFull(buf) 592 return decodeDateTim4(buf) 593 case typeFlt4: 594 return float64(math.Float32frombits(r.uint32())) 595 case typeFlt8: 596 return math.Float64frombits(r.uint64()) 597 case typeMoney4: 598 buf := make([]byte, size-2-propbytes) 599 r.ReadFull(buf) 600 return decodeMoney4(buf) 601 case typeMoney: 602 buf := make([]byte, size-2-propbytes) 603 r.ReadFull(buf) 604 return decodeMoney(buf) 605 case typeDateN: 606 buf := make([]byte, size-2-propbytes) 607 r.ReadFull(buf) 608 return decodeDate(buf) 609 case typeTimeN: 610 scale := r.byte() 611 buf := make([]byte, size-2-propbytes) 612 r.ReadFull(buf) 613 return decodeTime(scale, buf) 614 case typeDateTime2N: 615 scale := r.byte() 616 buf := make([]byte, size-2-propbytes) 617 r.ReadFull(buf) 618 return decodeDateTime2(scale, buf) 619 case typeDateTimeOffsetN: 620 scale := r.byte() 621 buf := make([]byte, size-2-propbytes) 622 r.ReadFull(buf) 623 return decodeDateTimeOffset(scale, buf) 624 case typeBigVarBin, typeBigBinary: 625 r.uint16() // max length, ignoring 626 buf := make([]byte, size-2-propbytes) 627 r.ReadFull(buf) 628 return buf 629 case typeDecimalN, typeNumericN: 630 prec := r.byte() 631 scale := r.byte() 632 buf := make([]byte, size-2-propbytes) 633 r.ReadFull(buf) 634 return decodeDecimal(prec, scale, buf) 635 case typeBigVarChar, typeBigChar: 636 col := readCollation(r) 637 r.uint16() // max length, ignoring 638 buf := make([]byte, size-2-propbytes) 639 r.ReadFull(buf) 640 return decodeChar(col, buf) 641 case typeNVarChar, typeNChar: 642 _ = readCollation(r) 643 r.uint16() // max length, ignoring 644 buf := make([]byte, size-2-propbytes) 645 r.ReadFull(buf) 646 return decodeNChar(buf) 647 default: 648 badStreamPanicf("Invalid variant typeid") 649 } 650 panic("shoulnd't get here") 651} 652 653// partially length prefixed stream 654// http://msdn.microsoft.com/en-us/library/dd340469.aspx 655func readPLPType(ti *typeInfo, r *tdsBuffer) interface{} { 656 size := r.uint64() 657 var buf *bytes.Buffer 658 switch size { 659 case _PLP_NULL: 660 // null 661 return nil 662 case _UNKNOWN_PLP_LEN: 663 // size unknown 664 buf = bytes.NewBuffer(make([]byte, 0, 1000)) 665 default: 666 buf = bytes.NewBuffer(make([]byte, 0, size)) 667 } 668 for { 669 chunksize := r.uint32() 670 if chunksize == 0 { 671 break 672 } 673 if _, err := io.CopyN(buf, r, int64(chunksize)); err != nil { 674 badStreamPanicf("Reading PLP type failed: %s", err.Error()) 675 } 676 } 677 switch ti.TypeId { 678 case typeXml: 679 return decodeXml(*ti, buf.Bytes()) 680 case typeBigVarChar, typeBigChar, typeText: 681 return decodeChar(ti.Collation, buf.Bytes()) 682 case typeBigVarBin, typeBigBinary, typeImage: 683 return buf.Bytes() 684 case typeNVarChar, typeNChar, typeNText: 685 return decodeNChar(buf.Bytes()) 686 case typeUdt: 687 return decodeUdt(*ti, buf.Bytes()) 688 } 689 panic("shoulnd't get here") 690} 691 692func writePLPType(w io.Writer, ti typeInfo, buf []byte) (err error) { 693 if buf == nil { 694 err = binary.Write(w, binary.LittleEndian, uint64(_PLP_NULL)) 695 return 696 } 697 if err = binary.Write(w, binary.LittleEndian, uint64(_UNKNOWN_PLP_LEN)); err != nil { 698 return 699 } 700 for { 701 chunksize := uint32(len(buf)) 702 if chunksize == 0 { 703 err = binary.Write(w, binary.LittleEndian, uint32(_PLP_TERMINATOR)) 704 return 705 } 706 if err = binary.Write(w, binary.LittleEndian, chunksize); err != nil { 707 return 708 } 709 if _, err = w.Write(buf[:chunksize]); err != nil { 710 return 711 } 712 buf = buf[chunksize:] 713 } 714} 715 716func readVarLen(ti *typeInfo, r *tdsBuffer) { 717 switch ti.TypeId { 718 case typeDateN: 719 ti.Size = 3 720 ti.Reader = readByteLenType 721 ti.Buffer = make([]byte, ti.Size) 722 case typeTimeN, typeDateTime2N, typeDateTimeOffsetN: 723 ti.Scale = r.byte() 724 switch ti.Scale { 725 case 0, 1, 2: 726 ti.Size = 3 727 case 3, 4: 728 ti.Size = 4 729 case 5, 6, 7: 730 ti.Size = 5 731 default: 732 badStreamPanicf("Invalid scale for TIME/DATETIME2/DATETIMEOFFSET type") 733 } 734 switch ti.TypeId { 735 case typeDateTime2N: 736 ti.Size += 3 737 case typeDateTimeOffsetN: 738 ti.Size += 5 739 } 740 ti.Reader = readByteLenType 741 ti.Buffer = make([]byte, ti.Size) 742 case typeGuid, typeIntN, typeDecimal, typeNumeric, 743 typeBitN, typeDecimalN, typeNumericN, typeFltN, 744 typeMoneyN, typeDateTimeN, typeChar, 745 typeVarChar, typeBinary, typeVarBinary: 746 // byle len types 747 ti.Size = int(r.byte()) 748 ti.Buffer = make([]byte, ti.Size) 749 switch ti.TypeId { 750 case typeDecimal, typeNumeric, typeDecimalN, typeNumericN: 751 ti.Prec = r.byte() 752 ti.Scale = r.byte() 753 } 754 ti.Reader = readByteLenType 755 case typeXml: 756 ti.XmlInfo.SchemaPresent = r.byte() 757 if ti.XmlInfo.SchemaPresent != 0 { 758 // dbname 759 ti.XmlInfo.DBName = r.BVarChar() 760 // owning schema 761 ti.XmlInfo.OwningSchema = r.BVarChar() 762 // xml schema collection 763 ti.XmlInfo.XmlSchemaCollection = r.UsVarChar() 764 } 765 ti.Reader = readPLPType 766 case typeUdt: 767 ti.Size = int(r.uint16()) 768 ti.UdtInfo.DBName = r.BVarChar() 769 ti.UdtInfo.SchemaName = r.BVarChar() 770 ti.UdtInfo.TypeName = r.BVarChar() 771 ti.UdtInfo.AssemblyQualifiedName = r.UsVarChar() 772 773 ti.Buffer = make([]byte, ti.Size) 774 ti.Reader = readPLPType 775 case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar, 776 typeNVarChar, typeNChar: 777 // short len types 778 ti.Size = int(r.uint16()) 779 switch ti.TypeId { 780 case typeBigVarChar, typeBigChar, typeNVarChar, typeNChar: 781 ti.Collation = readCollation(r) 782 } 783 if ti.Size == 0xffff { 784 ti.Reader = readPLPType 785 } else { 786 ti.Buffer = make([]byte, ti.Size) 787 ti.Reader = readShortLenType 788 } 789 case typeText, typeImage, typeNText, typeVariant: 790 // LONGLEN_TYPE 791 ti.Size = int(r.int32()) 792 switch ti.TypeId { 793 case typeText, typeNText: 794 ti.Collation = readCollation(r) 795 // ignore tablenames 796 numparts := int(r.byte()) 797 for i := 0; i < numparts; i++ { 798 r.UsVarChar() 799 } 800 ti.Reader = readLongLenType 801 case typeImage: 802 // ignore tablenames 803 numparts := int(r.byte()) 804 for i := 0; i < numparts; i++ { 805 r.UsVarChar() 806 } 807 ti.Reader = readLongLenType 808 case typeVariant: 809 ti.Reader = readVariantType 810 } 811 default: 812 badStreamPanicf("Invalid type %d", ti.TypeId) 813 } 814} 815 816func decodeMoney(buf []byte) []byte { 817 money := int64(uint64(buf[4]) | 818 uint64(buf[5])<<8 | 819 uint64(buf[6])<<16 | 820 uint64(buf[7])<<24 | 821 uint64(buf[0])<<32 | 822 uint64(buf[1])<<40 | 823 uint64(buf[2])<<48 | 824 uint64(buf[3])<<56) 825 return decimal.ScaleBytes(strconv.FormatInt(money, 10), 4) 826} 827 828func decodeMoney4(buf []byte) []byte { 829 money := int32(binary.LittleEndian.Uint32(buf[0:4])) 830 return decimal.ScaleBytes(strconv.FormatInt(int64(money), 10), 4) 831} 832 833func decodeGuid(buf []byte) []byte { 834 res := make([]byte, 16) 835 copy(res, buf) 836 return res 837} 838 839func decodeDecimal(prec uint8, scale uint8, buf []byte) []byte { 840 sign := buf[0] 841 var dec decimal.Decimal 842 dec.SetPositive(sign != 0) 843 dec.SetPrec(prec) 844 dec.SetScale(scale) 845 buf = buf[1:] 846 l := len(buf) / 4 847 for i := 0; i < l; i++ { 848 dec.SetInteger(binary.LittleEndian.Uint32(buf[0:4]), uint8(i)) 849 buf = buf[4:] 850 } 851 return dec.Bytes() 852} 853 854// http://msdn.microsoft.com/en-us/library/ee780895.aspx 855func decodeDateInt(buf []byte) (days int) { 856 days = int(buf[0]) + int(buf[1])*256 + int(buf[2])*256*256 857 return 858} 859 860func decodeDate(buf []byte) time.Time { 861 return time.Date(1, 1, 1+decodeDateInt(buf), 0, 0, 0, 0, time.UTC) 862} 863 864func encodeDate(val time.Time) (buf []byte) { 865 days, _, _ := dateTime2(val) 866 buf = make([]byte, 3) 867 buf[0] = byte(days) 868 buf[1] = byte(days >> 8) 869 buf[2] = byte(days >> 16) 870 return 871} 872 873func decodeTimeInt(scale uint8, buf []byte) (sec int, ns int) { 874 var acc uint64 = 0 875 for i := len(buf) - 1; i >= 0; i-- { 876 acc <<= 8 877 acc |= uint64(buf[i]) 878 } 879 for i := 0; i < 7-int(scale); i++ { 880 acc *= 10 881 } 882 nsbig := acc * 100 883 sec = int(nsbig / 1000000000) 884 ns = int(nsbig % 1000000000) 885 return 886} 887 888// calculate size of time field in bytes 889func calcTimeSize(scale int) int { 890 if scale <= 2 { 891 return 3 892 } else if scale <= 4 { 893 return 4 894 } else { 895 return 5 896 } 897} 898 899// writes time value into a field buffer 900// buffer should be at least calcTimeSize long 901func encodeTimeInt(seconds, ns, scale int, buf []byte) { 902 ns_total := int64(seconds)*1000*1000*1000 + int64(ns) 903 t := ns_total / int64(math.Pow10(int(scale)*-1)*1e9) 904 buf[0] = byte(t) 905 buf[1] = byte(t >> 8) 906 buf[2] = byte(t >> 16) 907 buf[3] = byte(t >> 24) 908 buf[4] = byte(t >> 32) 909} 910 911func decodeTime(scale uint8, buf []byte) time.Time { 912 sec, ns := decodeTimeInt(scale, buf) 913 return time.Date(1, 1, 1, 0, 0, sec, ns, time.UTC) 914} 915 916func encodeTime(hour, minute, second, ns, scale int) (buf []byte) { 917 seconds := hour*3600 + minute*60 + second 918 buf = make([]byte, calcTimeSize(scale)) 919 encodeTimeInt(seconds, ns, scale, buf) 920 return 921} 922 923func decodeDateTime2(scale uint8, buf []byte) time.Time { 924 timesize := len(buf) - 3 925 sec, ns := decodeTimeInt(scale, buf[:timesize]) 926 days := decodeDateInt(buf[timesize:]) 927 return time.Date(1, 1, 1+days, 0, 0, sec, ns, time.UTC) 928} 929 930func encodeDateTime2(val time.Time, scale int) (buf []byte) { 931 days, seconds, ns := dateTime2(val) 932 timesize := calcTimeSize(scale) 933 buf = make([]byte, 3+timesize) 934 encodeTimeInt(seconds, ns, scale, buf) 935 buf[timesize] = byte(days) 936 buf[timesize+1] = byte(days >> 8) 937 buf[timesize+2] = byte(days >> 16) 938 return 939} 940 941func decodeDateTimeOffset(scale uint8, buf []byte) time.Time { 942 timesize := len(buf) - 3 - 2 943 sec, ns := decodeTimeInt(scale, buf[:timesize]) 944 buf = buf[timesize:] 945 days := decodeDateInt(buf[:3]) 946 buf = buf[3:] 947 offset := int(int16(binary.LittleEndian.Uint16(buf))) // in mins 948 return time.Date(1, 1, 1+days, 0, 0, sec+offset*60, ns, 949 time.FixedZone("", offset*60)) 950} 951 952func encodeDateTimeOffset(val time.Time, scale int) (buf []byte) { 953 timesize := calcTimeSize(scale) 954 buf = make([]byte, timesize+2+3) 955 days, seconds, ns := dateTime2(val.In(time.UTC)) 956 encodeTimeInt(seconds, ns, scale, buf) 957 buf[timesize] = byte(days) 958 buf[timesize+1] = byte(days >> 8) 959 buf[timesize+2] = byte(days >> 16) 960 _, offset := val.Zone() 961 offset /= 60 962 buf[timesize+3] = byte(offset) 963 buf[timesize+4] = byte(offset >> 8) 964 return 965} 966 967// returns days since Jan 1st 0001 in Gregorian calendar 968func gregorianDays(year, yearday int) int { 969 year0 := year - 1 970 return year0*365 + year0/4 - year0/100 + year0/400 + yearday - 1 971} 972 973func dateTime2(t time.Time) (days int, seconds int, ns int) { 974 // days since Jan 1 1 (in same TZ as t) 975 days = gregorianDays(t.Year(), t.YearDay()) 976 seconds = t.Second() + t.Minute()*60 + t.Hour()*60*60 977 ns = t.Nanosecond() 978 if days < 0 { 979 days = 0 980 seconds = 0 981 ns = 0 982 } 983 max := gregorianDays(9999, 365) 984 if days > max { 985 days = max 986 seconds = 59 + 59*60 + 23*60*60 987 ns = 999999900 988 } 989 return 990} 991 992func decodeChar(col cp.Collation, buf []byte) string { 993 return cp.CharsetToUTF8(col, buf) 994} 995 996func decodeUcs2(buf []byte) string { 997 res, err := ucs22str(buf) 998 if err != nil { 999 badStreamPanicf("Invalid UCS2 encoding: %s", err.Error()) 1000 } 1001 return res 1002} 1003 1004func decodeNChar(buf []byte) string { 1005 return decodeUcs2(buf) 1006} 1007 1008func decodeXml(ti typeInfo, buf []byte) string { 1009 return decodeUcs2(buf) 1010} 1011 1012func decodeUdt(ti typeInfo, buf []byte) []byte { 1013 return buf 1014} 1015 1016// makes go/sql type instance as described below 1017// It should return 1018// the value type that can be used to scan types into. For example, the database 1019// column type "bigint" this should return "reflect.TypeOf(int64(0))". 1020func makeGoLangScanType(ti typeInfo) reflect.Type { 1021 switch ti.TypeId { 1022 case typeInt1: 1023 return reflect.TypeOf(int64(0)) 1024 case typeInt2: 1025 return reflect.TypeOf(int64(0)) 1026 case typeInt4: 1027 return reflect.TypeOf(int64(0)) 1028 case typeInt8: 1029 return reflect.TypeOf(int64(0)) 1030 case typeFlt4: 1031 return reflect.TypeOf(float64(0)) 1032 case typeIntN: 1033 switch ti.Size { 1034 case 1: 1035 return reflect.TypeOf(int64(0)) 1036 case 2: 1037 return reflect.TypeOf(int64(0)) 1038 case 4: 1039 return reflect.TypeOf(int64(0)) 1040 case 8: 1041 return reflect.TypeOf(int64(0)) 1042 default: 1043 panic("invalid size of INTNTYPE") 1044 } 1045 case typeFlt8: 1046 return reflect.TypeOf(float64(0)) 1047 case typeFltN: 1048 switch ti.Size { 1049 case 4: 1050 return reflect.TypeOf(float64(0)) 1051 case 8: 1052 return reflect.TypeOf(float64(0)) 1053 default: 1054 panic("invalid size of FLNNTYPE") 1055 } 1056 case typeBigVarBin: 1057 return reflect.TypeOf([]byte{}) 1058 case typeVarChar: 1059 return reflect.TypeOf("") 1060 case typeNVarChar: 1061 return reflect.TypeOf("") 1062 case typeBit, typeBitN: 1063 return reflect.TypeOf(true) 1064 case typeDecimalN, typeNumericN: 1065 return reflect.TypeOf([]byte{}) 1066 case typeMoney, typeMoney4, typeMoneyN: 1067 switch ti.Size { 1068 case 4: 1069 return reflect.TypeOf([]byte{}) 1070 case 8: 1071 return reflect.TypeOf([]byte{}) 1072 default: 1073 panic("invalid size of MONEYN") 1074 } 1075 case typeDateTim4: 1076 return reflect.TypeOf(time.Time{}) 1077 case typeDateTime: 1078 return reflect.TypeOf(time.Time{}) 1079 case typeDateTimeN: 1080 switch ti.Size { 1081 case 4: 1082 return reflect.TypeOf(time.Time{}) 1083 case 8: 1084 return reflect.TypeOf(time.Time{}) 1085 default: 1086 panic("invalid size of DATETIMEN") 1087 } 1088 case typeDateTime2N: 1089 return reflect.TypeOf(time.Time{}) 1090 case typeDateN: 1091 return reflect.TypeOf(time.Time{}) 1092 case typeTimeN: 1093 return reflect.TypeOf(time.Time{}) 1094 case typeDateTimeOffsetN: 1095 return reflect.TypeOf(time.Time{}) 1096 case typeBigVarChar: 1097 return reflect.TypeOf("") 1098 case typeBigChar: 1099 return reflect.TypeOf("") 1100 case typeNChar: 1101 return reflect.TypeOf("") 1102 case typeGuid: 1103 return reflect.TypeOf([]byte{}) 1104 case typeXml: 1105 return reflect.TypeOf("") 1106 case typeText: 1107 return reflect.TypeOf("") 1108 case typeNText: 1109 return reflect.TypeOf("") 1110 case typeImage: 1111 return reflect.TypeOf([]byte{}) 1112 case typeBigBinary: 1113 return reflect.TypeOf([]byte{}) 1114 case typeVariant: 1115 return reflect.TypeOf(nil) 1116 default: 1117 panic(fmt.Sprintf("not implemented makeGoLangScanType for type %d", ti.TypeId)) 1118 } 1119} 1120 1121func makeDecl(ti typeInfo) string { 1122 switch ti.TypeId { 1123 case typeNull: 1124 // maybe we should use something else here 1125 // this is tested in TestNull 1126 return "nvarchar(1)" 1127 case typeInt1: 1128 return "tinyint" 1129 case typeBigBinary: 1130 return fmt.Sprintf("binary(%d)", ti.Size) 1131 case typeInt2: 1132 return "smallint" 1133 case typeInt4: 1134 return "int" 1135 case typeInt8: 1136 return "bigint" 1137 case typeFlt4: 1138 return "real" 1139 case typeIntN: 1140 switch ti.Size { 1141 case 1: 1142 return "tinyint" 1143 case 2: 1144 return "smallint" 1145 case 4: 1146 return "int" 1147 case 8: 1148 return "bigint" 1149 default: 1150 panic("invalid size of INTNTYPE") 1151 } 1152 case typeFlt8: 1153 return "float" 1154 case typeFltN: 1155 switch ti.Size { 1156 case 4: 1157 return "real" 1158 case 8: 1159 return "float" 1160 default: 1161 panic("invalid size of FLNNTYPE") 1162 } 1163 case typeDecimal, typeDecimalN: 1164 return fmt.Sprintf("decimal(%d, %d)", ti.Prec, ti.Scale) 1165 case typeNumeric, typeNumericN: 1166 return fmt.Sprintf("numeric(%d, %d)", ti.Prec, ti.Scale) 1167 case typeMoney4: 1168 return "smallmoney" 1169 case typeMoney: 1170 return "money" 1171 case typeMoneyN: 1172 switch ti.Size { 1173 case 4: 1174 return "smallmoney" 1175 case 8: 1176 return "money" 1177 default: 1178 panic("invalid size of MONEYNTYPE") 1179 } 1180 case typeBigVarBin: 1181 if ti.Size > 8000 || ti.Size == 0 { 1182 return "varbinary(max)" 1183 } else { 1184 return fmt.Sprintf("varbinary(%d)", ti.Size) 1185 } 1186 case typeNChar: 1187 return fmt.Sprintf("nchar(%d)", ti.Size/2) 1188 case typeBigChar, typeChar: 1189 return fmt.Sprintf("char(%d)", ti.Size) 1190 case typeBigVarChar, typeVarChar: 1191 if ti.Size > 8000 || ti.Size == 0 { 1192 return "varchar(max)" 1193 } else { 1194 return fmt.Sprintf("varchar(%d)", ti.Size) 1195 } 1196 case typeNVarChar: 1197 if ti.Size > 8000 || ti.Size == 0 { 1198 return "nvarchar(max)" 1199 } else { 1200 return fmt.Sprintf("nvarchar(%d)", ti.Size/2) 1201 } 1202 case typeBit, typeBitN: 1203 return "bit" 1204 case typeDateN: 1205 return "date" 1206 case typeDateTim4: 1207 return "smalldatetime" 1208 case typeDateTime: 1209 return "datetime" 1210 case typeDateTimeN: 1211 switch ti.Size { 1212 case 4: 1213 return "smalldatetime" 1214 case 8: 1215 return "datetime" 1216 default: 1217 panic("invalid size of DATETIMNTYPE") 1218 } 1219 case typeTimeN: 1220 return "time" 1221 case typeDateTime2N: 1222 return fmt.Sprintf("datetime2(%d)", ti.Scale) 1223 case typeDateTimeOffsetN: 1224 return fmt.Sprintf("datetimeoffset(%d)", ti.Scale) 1225 case typeText: 1226 return "text" 1227 case typeNText: 1228 return "ntext" 1229 case typeUdt: 1230 return ti.UdtInfo.TypeName 1231 case typeGuid: 1232 return "uniqueidentifier" 1233 case typeTvp: 1234 if ti.UdtInfo.SchemaName != "" { 1235 return fmt.Sprintf("%s.%s READONLY", ti.UdtInfo.SchemaName, ti.UdtInfo.TypeName) 1236 } 1237 return fmt.Sprintf("%s READONLY", ti.UdtInfo.TypeName) 1238 default: 1239 panic(fmt.Sprintf("not implemented makeDecl for type %#x", ti.TypeId)) 1240 } 1241} 1242 1243// makes go/sql type name as described below 1244// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the 1245// database system type name without the length. Type names should be uppercase. 1246// Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT", 1247// "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML", 1248// "TIMESTAMP". 1249func makeGoLangTypeName(ti typeInfo) string { 1250 switch ti.TypeId { 1251 case typeInt1: 1252 return "TINYINT" 1253 case typeInt2: 1254 return "SMALLINT" 1255 case typeInt4: 1256 return "INT" 1257 case typeInt8: 1258 return "BIGINT" 1259 case typeFlt4: 1260 return "REAL" 1261 case typeIntN: 1262 switch ti.Size { 1263 case 1: 1264 return "TINYINT" 1265 case 2: 1266 return "SMALLINT" 1267 case 4: 1268 return "INT" 1269 case 8: 1270 return "BIGINT" 1271 default: 1272 panic("invalid size of INTNTYPE") 1273 } 1274 case typeFlt8: 1275 return "FLOAT" 1276 case typeFltN: 1277 switch ti.Size { 1278 case 4: 1279 return "REAL" 1280 case 8: 1281 return "FLOAT" 1282 default: 1283 panic("invalid size of FLNNTYPE") 1284 } 1285 case typeBigVarBin: 1286 return "VARBINARY" 1287 case typeVarChar: 1288 return "VARCHAR" 1289 case typeNVarChar: 1290 return "NVARCHAR" 1291 case typeBit, typeBitN: 1292 return "BIT" 1293 case typeDecimalN, typeNumericN: 1294 return "DECIMAL" 1295 case typeMoney, typeMoney4, typeMoneyN: 1296 switch ti.Size { 1297 case 4: 1298 return "SMALLMONEY" 1299 case 8: 1300 return "MONEY" 1301 default: 1302 panic("invalid size of MONEYN") 1303 } 1304 case typeDateTim4: 1305 return "SMALLDATETIME" 1306 case typeDateTime: 1307 return "DATETIME" 1308 case typeDateTimeN: 1309 switch ti.Size { 1310 case 4: 1311 return "SMALLDATETIME" 1312 case 8: 1313 return "DATETIME" 1314 default: 1315 panic("invalid size of DATETIMEN") 1316 } 1317 case typeDateTime2N: 1318 return "DATETIME2" 1319 case typeDateN: 1320 return "DATE" 1321 case typeTimeN: 1322 return "TIME" 1323 case typeDateTimeOffsetN: 1324 return "DATETIMEOFFSET" 1325 case typeBigVarChar: 1326 return "VARCHAR" 1327 case typeBigChar: 1328 return "CHAR" 1329 case typeNChar: 1330 return "NCHAR" 1331 case typeGuid: 1332 return "UNIQUEIDENTIFIER" 1333 case typeXml: 1334 return "XML" 1335 case typeText: 1336 return "TEXT" 1337 case typeNText: 1338 return "NTEXT" 1339 case typeImage: 1340 return "IMAGE" 1341 case typeVariant: 1342 return "SQL_VARIANT" 1343 case typeBigBinary: 1344 return "BINARY" 1345 default: 1346 panic(fmt.Sprintf("not implemented makeGoLangTypeName for type %d", ti.TypeId)) 1347 } 1348} 1349 1350// makes go/sql type length as described below 1351// It should return the length 1352// of the column type if the column is a variable length type. If the column is 1353// not a variable length type ok should return false. 1354// If length is not limited other than system limits, it should return math.MaxInt64. 1355// The following are examples of returned values for various types: 1356// TEXT (math.MaxInt64, true) 1357// varchar(10) (10, true) 1358// nvarchar(10) (10, true) 1359// decimal (0, false) 1360// int (0, false) 1361// bytea(30) (30, true) 1362func makeGoLangTypeLength(ti typeInfo) (int64, bool) { 1363 switch ti.TypeId { 1364 case typeInt1: 1365 return 0, false 1366 case typeInt2: 1367 return 0, false 1368 case typeInt4: 1369 return 0, false 1370 case typeInt8: 1371 return 0, false 1372 case typeFlt4: 1373 return 0, false 1374 case typeIntN: 1375 switch ti.Size { 1376 case 1: 1377 return 0, false 1378 case 2: 1379 return 0, false 1380 case 4: 1381 return 0, false 1382 case 8: 1383 return 0, false 1384 default: 1385 panic("invalid size of INTNTYPE") 1386 } 1387 case typeFlt8: 1388 return 0, false 1389 case typeFltN: 1390 switch ti.Size { 1391 case 4: 1392 return 0, false 1393 case 8: 1394 return 0, false 1395 default: 1396 panic("invalid size of FLNNTYPE") 1397 } 1398 case typeBit, typeBitN: 1399 return 0, false 1400 case typeDecimalN, typeNumericN: 1401 return 0, false 1402 case typeMoney, typeMoney4, typeMoneyN: 1403 switch ti.Size { 1404 case 4: 1405 return 0, false 1406 case 8: 1407 return 0, false 1408 default: 1409 panic("invalid size of MONEYN") 1410 } 1411 case typeDateTim4, typeDateTime: 1412 return 0, false 1413 case typeDateTimeN: 1414 switch ti.Size { 1415 case 4: 1416 return 0, false 1417 case 8: 1418 return 0, false 1419 default: 1420 panic("invalid size of DATETIMEN") 1421 } 1422 case typeDateTime2N: 1423 return 0, false 1424 case typeDateN: 1425 return 0, false 1426 case typeTimeN: 1427 return 0, false 1428 case typeDateTimeOffsetN: 1429 return 0, false 1430 case typeBigVarBin: 1431 if ti.Size == 0xffff { 1432 return 2147483645, true 1433 } else { 1434 return int64(ti.Size), true 1435 } 1436 case typeVarChar: 1437 return int64(ti.Size), true 1438 case typeBigVarChar: 1439 if ti.Size == 0xffff { 1440 return 2147483645, true 1441 } else { 1442 return int64(ti.Size), true 1443 } 1444 case typeBigChar: 1445 return int64(ti.Size), true 1446 case typeNVarChar: 1447 if ti.Size == 0xffff { 1448 return 2147483645 / 2, true 1449 } else { 1450 return int64(ti.Size) / 2, true 1451 } 1452 case typeNChar: 1453 return int64(ti.Size) / 2, true 1454 case typeGuid: 1455 return 0, false 1456 case typeXml: 1457 return 1073741822, true 1458 case typeText: 1459 return 2147483647, true 1460 case typeNText: 1461 return 1073741823, true 1462 case typeImage: 1463 return 2147483647, true 1464 case typeVariant: 1465 return 0, false 1466 case typeBigBinary: 1467 return int64(ti.Size), true 1468 default: 1469 panic(fmt.Sprintf("not implemented makeGoLangTypeLength for type %d", ti.TypeId)) 1470 } 1471} 1472 1473// makes go/sql type precision and scale as described below 1474// It should return the length 1475// of the column type if the column is a variable length type. If the column is 1476// not a variable length type ok should return false. 1477// If length is not limited other than system limits, it should return math.MaxInt64. 1478// The following are examples of returned values for various types: 1479// TEXT (math.MaxInt64, true) 1480// varchar(10) (10, true) 1481// nvarchar(10) (10, true) 1482// decimal (0, false) 1483// int (0, false) 1484// bytea(30) (30, true) 1485func makeGoLangTypePrecisionScale(ti typeInfo) (int64, int64, bool) { 1486 switch ti.TypeId { 1487 case typeInt1: 1488 return 0, 0, false 1489 case typeInt2: 1490 return 0, 0, false 1491 case typeInt4: 1492 return 0, 0, false 1493 case typeInt8: 1494 return 0, 0, false 1495 case typeFlt4: 1496 return 0, 0, false 1497 case typeIntN: 1498 switch ti.Size { 1499 case 1: 1500 return 0, 0, false 1501 case 2: 1502 return 0, 0, false 1503 case 4: 1504 return 0, 0, false 1505 case 8: 1506 return 0, 0, false 1507 default: 1508 panic("invalid size of INTNTYPE") 1509 } 1510 case typeFlt8: 1511 return 0, 0, false 1512 case typeFltN: 1513 switch ti.Size { 1514 case 4: 1515 return 0, 0, false 1516 case 8: 1517 return 0, 0, false 1518 default: 1519 panic("invalid size of FLNNTYPE") 1520 } 1521 case typeBit, typeBitN: 1522 return 0, 0, false 1523 case typeDecimalN, typeNumericN: 1524 return int64(ti.Prec), int64(ti.Scale), true 1525 case typeMoney, typeMoney4, typeMoneyN: 1526 switch ti.Size { 1527 case 4: 1528 return 0, 0, false 1529 case 8: 1530 return 0, 0, false 1531 default: 1532 panic("invalid size of MONEYN") 1533 } 1534 case typeDateTim4, typeDateTime: 1535 return 0, 0, false 1536 case typeDateTimeN: 1537 switch ti.Size { 1538 case 4: 1539 return 0, 0, false 1540 case 8: 1541 return 0, 0, false 1542 default: 1543 panic("invalid size of DATETIMEN") 1544 } 1545 case typeDateTime2N: 1546 return 0, 0, false 1547 case typeDateN: 1548 return 0, 0, false 1549 case typeTimeN: 1550 return 0, 0, false 1551 case typeDateTimeOffsetN: 1552 return 0, 0, false 1553 case typeBigVarBin: 1554 return 0, 0, false 1555 case typeVarChar: 1556 return 0, 0, false 1557 case typeBigVarChar: 1558 return 0, 0, false 1559 case typeBigChar: 1560 return 0, 0, false 1561 case typeNVarChar: 1562 return 0, 0, false 1563 case typeNChar: 1564 return 0, 0, false 1565 case typeGuid: 1566 return 0, 0, false 1567 case typeXml: 1568 return 0, 0, false 1569 case typeText: 1570 return 0, 0, false 1571 case typeNText: 1572 return 0, 0, false 1573 case typeImage: 1574 return 0, 0, false 1575 case typeVariant: 1576 return 0, 0, false 1577 case typeBigBinary: 1578 return 0, 0, false 1579 default: 1580 panic(fmt.Sprintf("not implemented makeGoLangTypePrecisionScale for type %d", ti.TypeId)) 1581 } 1582} 1583