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