1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261 |
- package mssql
- import (
- "bytes"
- "encoding/binary"
- "fmt"
- "io"
- "math"
- "strconv"
- "time"
- "reflect"
- )
- // fixed-length data types
- // http://msdn.microsoft.com/en-us/library/dd341171.aspx
- const (
- typeNull = 0x1f
- typeInt1 = 0x30
- typeBit = 0x32
- typeInt2 = 0x34
- typeInt4 = 0x38
- typeDateTim4 = 0x3a
- typeFlt4 = 0x3b
- typeMoney = 0x3c
- typeDateTime = 0x3d
- typeFlt8 = 0x3e
- typeMoney4 = 0x7a
- typeInt8 = 0x7f
- )
- // variable-length data types
- // http://msdn.microsoft.com/en-us/library/dd358341.aspx
- const (
- // byte len types
- typeGuid = 0x24
- typeIntN = 0x26
- typeDecimal = 0x37 // legacy
- typeNumeric = 0x3f // legacy
- typeBitN = 0x68
- typeDecimalN = 0x6a
- typeNumericN = 0x6c
- typeFltN = 0x6d
- typeMoneyN = 0x6e
- typeDateTimeN = 0x6f
- typeDateN = 0x28
- typeTimeN = 0x29
- typeDateTime2N = 0x2a
- typeDateTimeOffsetN = 0x2b
- typeChar = 0x2f // legacy
- typeVarChar = 0x27 // legacy
- typeBinary = 0x2d // legacy
- typeVarBinary = 0x25 // legacy
- // short length types
- typeBigVarBin = 0xa5
- typeBigVarChar = 0xa7
- typeBigBinary = 0xad
- typeBigChar = 0xaf
- typeNVarChar = 0xe7
- typeNChar = 0xef
- typeXml = 0xf1
- typeUdt = 0xf0
- // long length types
- typeText = 0x23
- typeImage = 0x22
- typeNText = 0x63
- typeVariant = 0x62
- )
- // TYPE_INFO rule
- // http://msdn.microsoft.com/en-us/library/dd358284.aspx
- type typeInfo struct {
- TypeId uint8
- Size int
- Scale uint8
- Prec uint8
- Buffer []byte
- Collation collation
- Reader func(ti *typeInfo, r *tdsBuffer) (res interface{})
- Writer func(w io.Writer, ti typeInfo, buf []byte) (err error)
- }
- func readTypeInfo(r *tdsBuffer) (res typeInfo) {
- res.TypeId = r.byte()
- switch res.TypeId {
- case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4,
- typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8:
- // those are fixed length types
- switch res.TypeId {
- case typeNull:
- res.Size = 0
- case typeInt1, typeBit:
- res.Size = 1
- case typeInt2:
- res.Size = 2
- case typeInt4, typeDateTim4, typeFlt4, typeMoney4:
- res.Size = 4
- case typeMoney, typeDateTime, typeFlt8, typeInt8:
- res.Size = 8
- }
- res.Reader = readFixedType
- res.Buffer = make([]byte, res.Size)
- default: // all others are VARLENTYPE
- readVarLen(&res, r)
- }
- return
- }
- func writeTypeInfo(w io.Writer, ti *typeInfo) (err error) {
- err = binary.Write(w, binary.LittleEndian, ti.TypeId)
- if err != nil {
- return
- }
- switch ti.TypeId {
- case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4,
- typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8:
- // those are fixed length types
- default: // all others are VARLENTYPE
- err = writeVarLen(w, ti)
- if err != nil {
- return
- }
- }
- return
- }
- func writeVarLen(w io.Writer, ti *typeInfo) (err error) {
- switch ti.TypeId {
- case typeDateN:
- case typeTimeN, typeDateTime2N, typeDateTimeOffsetN:
- if err = binary.Write(w, binary.LittleEndian, ti.Scale); err != nil {
- return
- }
- ti.Writer = writeByteLenType
- case typeIntN, typeDecimal, typeNumeric,
- typeBitN, typeDecimalN, typeNumericN, typeFltN,
- typeMoneyN, typeDateTimeN, typeChar,
- typeVarChar, typeBinary, typeVarBinary:
- // byle len types
- if ti.Size > 0xff {
- panic("Invalid size for BYLELEN_TYPE")
- }
- if err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)); err != nil {
- return
- }
- switch ti.TypeId {
- case typeDecimal, typeNumeric, typeDecimalN, typeNumericN:
- err = binary.Write(w, binary.LittleEndian, ti.Prec)
- if err != nil {
- return
- }
- err = binary.Write(w, binary.LittleEndian, ti.Scale)
- if err != nil {
- return
- }
- }
- ti.Writer = writeByteLenType
- case typeGuid:
- if !(ti.Size == 0x10 || ti.Size == 0x00) {
- panic("Invalid size for BYLELEN_TYPE")
- }
- if err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)); err != nil {
- return
- }
- ti.Writer = writeByteLenType
- case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar,
- typeNVarChar, typeNChar, typeXml, typeUdt:
- // short len types
- if ti.Size > 8000 || ti.Size == 0 {
- if err = binary.Write(w, binary.LittleEndian, uint16(0xffff)); err != nil {
- return
- }
- ti.Writer = writePLPType
- } else {
- if err = binary.Write(w, binary.LittleEndian, uint16(ti.Size)); err != nil {
- return
- }
- ti.Writer = writeShortLenType
- }
- switch ti.TypeId {
- case typeBigVarChar, typeBigChar, typeNVarChar, typeNChar:
- if err = writeCollation(w, ti.Collation); err != nil {
- return
- }
- case typeXml:
- var schemapresent uint8 = 0
- if err = binary.Write(w, binary.LittleEndian, schemapresent); err != nil {
- return
- }
- }
- case typeText, typeImage, typeNText, typeVariant:
- // LONGLEN_TYPE
- panic("LONGLEN_TYPE not implemented")
- default:
- panic("Invalid type")
- }
- return
- }
- // http://msdn.microsoft.com/en-us/library/ee780895.aspx
- func decodeDateTim4(buf []byte) time.Time {
- days := binary.LittleEndian.Uint16(buf)
- mins := binary.LittleEndian.Uint16(buf[2:])
- return time.Date(1900, 1, 1+int(days),
- 0, int(mins), 0, 0, time.UTC)
- }
- func decodeDateTime(buf []byte) time.Time {
- days := int32(binary.LittleEndian.Uint32(buf))
- tm := binary.LittleEndian.Uint32(buf[4:])
- ns := int(math.Trunc(float64(tm%300)/0.3+0.5)) * 1000000
- secs := int(tm / 300)
- return time.Date(1900, 1, 1+int(days),
- 0, 0, secs, ns, time.UTC)
- }
- func readFixedType(ti *typeInfo, r *tdsBuffer) (interface{}) {
- r.ReadFull(ti.Buffer)
- buf := ti.Buffer
- switch ti.TypeId {
- case typeNull:
- return nil
- case typeInt1:
- return int64(buf[0])
- case typeBit:
- return buf[0] != 0
- case typeInt2:
- return int64(int16(binary.LittleEndian.Uint16(buf)))
- case typeInt4:
- return int64(int32(binary.LittleEndian.Uint32(buf)))
- case typeDateTim4:
- return decodeDateTim4(buf)
- case typeFlt4:
- return math.Float32frombits(binary.LittleEndian.Uint32(buf))
- case typeMoney4:
- return decodeMoney4(buf)
- case typeMoney:
- return decodeMoney(buf)
- case typeDateTime:
- return decodeDateTime(buf)
- case typeFlt8:
- return math.Float64frombits(binary.LittleEndian.Uint64(buf))
- case typeInt8:
- return int64(binary.LittleEndian.Uint64(buf))
- default:
- badStreamPanicf("Invalid typeid")
- }
- panic("shoulnd't get here")
- }
- func readByteLenType(ti *typeInfo, r *tdsBuffer) (interface{}) {
- size := r.byte()
- if size == 0 {
- return nil
- }
- r.ReadFull(ti.Buffer[:size])
- buf := ti.Buffer[:size]
- switch ti.TypeId {
- case typeDateN:
- if len(buf) != 3 {
- badStreamPanicf("Invalid size for DATENTYPE")
- }
- return decodeDate(buf)
- case typeTimeN:
- return decodeTime(ti.Scale, buf)
- case typeDateTime2N:
- return decodeDateTime2(ti.Scale, buf)
- case typeDateTimeOffsetN:
- return decodeDateTimeOffset(ti.Scale, buf)
- case typeGuid:
- return decodeGuid(buf)
- case typeIntN:
- switch len(buf) {
- case 1:
- return int64(buf[0])
- case 2:
- return int64(int16((binary.LittleEndian.Uint16(buf))))
- case 4:
- return int64(int32(binary.LittleEndian.Uint32(buf)))
- case 8:
- return int64(binary.LittleEndian.Uint64(buf))
- default:
- badStreamPanicf("Invalid size for INTNTYPE")
- }
- case typeDecimal, typeNumeric, typeDecimalN, typeNumericN:
- return decodeDecimal(ti.Prec, ti.Scale, buf)
- case typeBitN:
- if len(buf) != 1 {
- badStreamPanicf("Invalid size for BITNTYPE")
- }
- return buf[0] != 0
- case typeFltN:
- switch len(buf) {
- case 4:
- return float64(math.Float32frombits(binary.LittleEndian.Uint32(buf)))
- case 8:
- return math.Float64frombits(binary.LittleEndian.Uint64(buf))
- default:
- badStreamPanicf("Invalid size for FLTNTYPE")
- }
- case typeMoneyN:
- switch len(buf) {
- case 4:
- return decodeMoney4(buf)
- case 8:
- return decodeMoney(buf)
- default:
- badStreamPanicf("Invalid size for MONEYNTYPE")
- }
- case typeDateTimeN:
- switch len(buf) {
- case 4:
- return decodeDateTim4(buf)
- case 8:
- return decodeDateTime(buf)
- default:
- badStreamPanicf("Invalid size for DATETIMENTYPE")
- }
- case typeChar, typeVarChar:
- return decodeChar(ti.Collation, buf)
- case typeBinary, typeVarBinary:
- // a copy, because the backing array for ti.Buffer is reused
- // and can be overwritten by the next row while this row waits
- // in a buffered chan
- cpy := make([]byte, len(buf))
- copy(cpy, buf)
- return cpy
- default:
- badStreamPanicf("Invalid typeid")
- }
- panic("shoulnd't get here")
- }
- func writeByteLenType(w io.Writer, ti typeInfo, buf []byte) (err error) {
- if ti.Size > 0xff {
- panic("Invalid size for BYTELEN_TYPE")
- }
- err = binary.Write(w, binary.LittleEndian, uint8(ti.Size))
- if err != nil {
- return
- }
- _, err = w.Write(buf)
- return
- }
- func readShortLenType(ti *typeInfo, r *tdsBuffer) (interface{}) {
- size := r.uint16()
- if size == 0xffff {
- return nil
- }
- r.ReadFull(ti.Buffer[:size])
- buf := ti.Buffer[:size]
- switch ti.TypeId {
- case typeBigVarChar, typeBigChar:
- return decodeChar(ti.Collation, buf)
- case typeBigVarBin, typeBigBinary:
- // a copy, because the backing array for ti.Buffer is reused
- // and can be overwritten by the next row while this row waits
- // in a buffered chan
- cpy := make([]byte, len(buf))
- copy(cpy, buf)
- return cpy
- case typeNVarChar, typeNChar:
- return decodeNChar(buf)
- case typeUdt:
- return decodeUdt(*ti, buf)
- default:
- badStreamPanicf("Invalid typeid")
- }
- panic("shoulnd't get here")
- }
- func writeShortLenType(w io.Writer, ti typeInfo, buf []byte) (err error) {
- if buf == nil {
- err = binary.Write(w, binary.LittleEndian, uint16(0xffff))
- return
- }
- if ti.Size > 0xfffe {
- panic("Invalid size for USHORTLEN_TYPE")
- }
- err = binary.Write(w, binary.LittleEndian, uint16(ti.Size))
- if err != nil {
- return
- }
- _, err = w.Write(buf)
- return
- }
- func readLongLenType(ti *typeInfo, r *tdsBuffer) (interface{}) {
- // information about this format can be found here:
- // http://msdn.microsoft.com/en-us/library/dd304783.aspx
- // and here:
- // http://msdn.microsoft.com/en-us/library/dd357254.aspx
- textptrsize := int(r.byte())
- if textptrsize == 0 {
- return nil
- }
- textptr := make([]byte, textptrsize)
- r.ReadFull(textptr)
- timestamp := r.uint64()
- _ = timestamp // ignore timestamp
- size := r.int32()
- if size == -1 {
- return nil
- }
- buf := make([]byte, size)
- r.ReadFull(buf)
- switch ti.TypeId {
- case typeText:
- return decodeChar(ti.Collation, buf)
- case typeImage:
- return buf
- case typeNText:
- return decodeNChar(buf)
- default:
- badStreamPanicf("Invalid typeid")
- }
- panic("shoulnd't get here")
- }
- // reads variant value
- // http://msdn.microsoft.com/en-us/library/dd303302.aspx
- func readVariantType(ti *typeInfo, r *tdsBuffer) (interface{}) {
- size := r.int32()
- if size == 0 {
- return nil
- }
- vartype := r.byte()
- propbytes := int32(r.byte())
- switch vartype {
- case typeGuid:
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return buf
- case typeBit:
- return r.byte() != 0
- case typeInt1:
- return int64(r.byte())
- case typeInt2:
- return int64(int16(r.uint16()))
- case typeInt4:
- return int64(r.int32())
- case typeInt8:
- return int64(r.uint64())
- case typeDateTime:
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return decodeDateTime(buf)
- case typeDateTim4:
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return decodeDateTim4(buf)
- case typeFlt4:
- return float64(math.Float32frombits(r.uint32()))
- case typeFlt8:
- return math.Float64frombits(r.uint64())
- case typeMoney4:
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return decodeMoney4(buf)
- case typeMoney:
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return decodeMoney(buf)
- case typeDateN:
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return decodeDate(buf)
- case typeTimeN:
- scale := r.byte()
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return decodeTime(scale, buf)
- case typeDateTime2N:
- scale := r.byte()
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return decodeDateTime2(scale, buf)
- case typeDateTimeOffsetN:
- scale := r.byte()
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return decodeDateTimeOffset(scale, buf)
- case typeBigVarBin, typeBigBinary:
- r.uint16() // max length, ignoring
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return buf
- case typeDecimalN, typeNumericN:
- prec := r.byte()
- scale := r.byte()
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return decodeDecimal(prec, scale, buf)
- case typeBigVarChar, typeBigChar:
- col := readCollation(r)
- r.uint16() // max length, ignoring
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return decodeChar(col, buf)
- case typeNVarChar, typeNChar:
- _ = readCollation(r)
- r.uint16() // max length, ignoring
- buf := make([]byte, size-2-propbytes)
- r.ReadFull(buf)
- return decodeNChar(buf)
- default:
- badStreamPanicf("Invalid variant typeid")
- }
- panic("shoulnd't get here")
- }
- // partially length prefixed stream
- // http://msdn.microsoft.com/en-us/library/dd340469.aspx
- func readPLPType(ti *typeInfo, r *tdsBuffer) (interface{}) {
- size := r.uint64()
- var buf *bytes.Buffer
- switch size {
- case 0xffffffffffffffff:
- // null
- return nil
- case 0xfffffffffffffffe:
- // size unknown
- buf = bytes.NewBuffer(make([]byte, 0, 1000))
- default:
- buf = bytes.NewBuffer(make([]byte, 0, size))
- }
- for true {
- chunksize := r.uint32()
- if chunksize == 0 {
- break
- }
- if _, err := io.CopyN(buf, r, int64(chunksize)); err != nil {
- badStreamPanicf("Reading PLP type failed: %s", err.Error())
- }
- }
- switch ti.TypeId {
- case typeXml:
- return decodeXml(*ti, buf.Bytes())
- case typeBigVarChar, typeBigChar, typeText:
- return decodeChar(ti.Collation, buf.Bytes())
- case typeBigVarBin, typeBigBinary, typeImage:
- return buf.Bytes()
- case typeNVarChar, typeNChar, typeNText:
- return decodeNChar(buf.Bytes())
- case typeUdt:
- return decodeUdt(*ti, buf.Bytes())
- }
- panic("shoulnd't get here")
- }
- func writePLPType(w io.Writer, ti typeInfo, buf []byte) (err error) {
- if err = binary.Write(w, binary.LittleEndian, uint64(len(buf))); err != nil {
- return
- }
- for {
- chunksize := uint32(len(buf))
- if err = binary.Write(w, binary.LittleEndian, chunksize); err != nil {
- return
- }
- if chunksize == 0 {
- return
- }
- if _, err = w.Write(buf[:chunksize]); err != nil {
- return
- }
- buf = buf[chunksize:]
- }
- }
- func readVarLen(ti *typeInfo, r *tdsBuffer) {
- switch ti.TypeId {
- case typeDateN:
- ti.Size = 3
- ti.Reader = readByteLenType
- ti.Buffer = make([]byte, ti.Size)
- case typeTimeN, typeDateTime2N, typeDateTimeOffsetN:
- ti.Scale = r.byte()
- switch ti.Scale {
- case 0, 1, 2:
- ti.Size = 3
- case 3, 4:
- ti.Size = 4
- case 5, 6, 7:
- ti.Size = 5
- default:
- badStreamPanicf("Invalid scale for TIME/DATETIME2/DATETIMEOFFSET type")
- }
- switch ti.TypeId {
- case typeDateTime2N:
- ti.Size += 3
- case typeDateTimeOffsetN:
- ti.Size += 5
- }
- ti.Reader = readByteLenType
- ti.Buffer = make([]byte, ti.Size)
- case typeGuid, typeIntN, typeDecimal, typeNumeric,
- typeBitN, typeDecimalN, typeNumericN, typeFltN,
- typeMoneyN, typeDateTimeN, typeChar,
- typeVarChar, typeBinary, typeVarBinary:
- // byle len types
- ti.Size = int(r.byte())
- ti.Buffer = make([]byte, ti.Size)
- switch ti.TypeId {
- case typeDecimal, typeNumeric, typeDecimalN, typeNumericN:
- ti.Prec = r.byte()
- ti.Scale = r.byte()
- }
- ti.Reader = readByteLenType
- case typeXml:
- schemapresent := r.byte()
- if schemapresent != 0 {
- // just ignore this for now
- // dbname
- r.BVarChar()
- // owning schema
- r.BVarChar()
- // xml schema collection
- r.UsVarChar()
- }
- ti.Reader = readPLPType
- case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar,
- typeNVarChar, typeNChar, typeUdt:
- // short len types
- ti.Size = int(r.uint16())
- switch ti.TypeId {
- case typeBigVarChar, typeBigChar, typeNVarChar, typeNChar:
- ti.Collation = readCollation(r)
- }
- if ti.Size == 0xffff {
- ti.Reader = readPLPType
- } else {
- ti.Buffer = make([]byte, ti.Size)
- ti.Reader = readShortLenType
- }
- case typeText, typeImage, typeNText, typeVariant:
- // LONGLEN_TYPE
- ti.Size = int(r.int32())
- switch ti.TypeId {
- case typeText, typeNText:
- ti.Collation = readCollation(r)
- // ignore tablenames
- numparts := int(r.byte())
- for i := 0; i < numparts; i++ {
- r.UsVarChar()
- }
- ti.Reader = readLongLenType
- case typeImage:
- // ignore tablenames
- numparts := int(r.byte())
- for i := 0; i < numparts; i++ {
- r.UsVarChar()
- }
- ti.Reader = readLongLenType
- case typeVariant:
- ti.Reader = readVariantType
- }
- default:
- badStreamPanicf("Invalid type %d", ti.TypeId)
- }
- return
- }
- func decodeMoney(buf []byte) []byte {
- money := int64(uint64(buf[4]) |
- uint64(buf[5])<<8 |
- uint64(buf[6])<<16 |
- uint64(buf[7])<<24 |
- uint64(buf[0])<<32 |
- uint64(buf[1])<<40 |
- uint64(buf[2])<<48 |
- uint64(buf[3])<<56)
- return scaleBytes(strconv.FormatInt(money, 10), 4)
- }
- func decodeMoney4(buf []byte) []byte {
- money := int32(binary.LittleEndian.Uint32(buf[0:4]))
- return scaleBytes(strconv.FormatInt(int64(money), 10), 4)
- }
- func decodeGuid(buf []byte) []byte {
- res := make([]byte, 16)
- copy(res, buf)
- return res
- }
- func decodeDecimal(prec uint8, scale uint8, buf []byte) []byte {
- var sign uint8
- sign = buf[0]
- dec := Decimal{
- positive: sign != 0,
- prec: prec,
- scale: scale,
- }
- buf = buf[1:]
- l := len(buf) / 4
- for i := 0; i < l; i++ {
- dec.integer[i] = binary.LittleEndian.Uint32(buf[0:4])
- buf = buf[4:]
- }
- return dec.Bytes()
- }
- // http://msdn.microsoft.com/en-us/library/ee780895.aspx
- func decodeDateInt(buf []byte) (days int) {
- days = int(buf[0]) + int(buf[1])*256 + int(buf[2])*256*256
- return
- }
- func decodeDate(buf []byte) time.Time {
- return time.Date(1, 1, 1+decodeDateInt(buf), 0, 0, 0, 0, time.UTC)
- }
- func decodeTimeInt(scale uint8, buf []byte) (sec int, ns int) {
- var acc uint64 = 0
- for i := len(buf) - 1; i >= 0; i-- {
- acc <<= 8
- acc |= uint64(buf[i])
- }
- for i := 0; i < 7-int(scale); i++ {
- acc *= 10
- }
- nsbig := acc * 100
- sec = int(nsbig / 1000000000)
- ns = int(nsbig % 1000000000)
- return
- }
- func decodeTime(scale uint8, buf []byte) time.Time {
- sec, ns := decodeTimeInt(scale, buf)
- return time.Date(1, 1, 1, 0, 0, sec, ns, time.UTC)
- }
- func decodeDateTime2(scale uint8, buf []byte) time.Time {
- timesize := len(buf) - 3
- sec, ns := decodeTimeInt(scale, buf[:timesize])
- days := decodeDateInt(buf[timesize:])
- return time.Date(1, 1, 1+days, 0, 0, sec, ns, time.UTC)
- }
- func decodeDateTimeOffset(scale uint8, buf []byte) time.Time {
- timesize := len(buf) - 3 - 2
- sec, ns := decodeTimeInt(scale, buf[:timesize])
- buf = buf[timesize:]
- days := decodeDateInt(buf[:3])
- buf = buf[3:]
- offset := int(int16(binary.LittleEndian.Uint16(buf))) // in mins
- return time.Date(1, 1, 1+days, 0, 0, sec+offset*60, ns,
- time.FixedZone("", offset*60))
- }
- func divFloor(x int64, y int64) int64 {
- q := x / y
- r := x % y
- if r != 0 && ((r < 0) != (y < 0)) {
- q--
- }
- return q
- }
- func dateTime2(t time.Time) (days int32, ns int64) {
- // number of days since Jan 1 1970 UTC
- days64 := divFloor(t.Unix(), 24*60*60)
- // number of days since Jan 1 1 UTC
- days = int32(days64) + 1969*365 + 1969/4 - 1969/100 + 1969/400
- // number of seconds within day
- secs := t.Unix() - days64*24*60*60
- // number of nanoseconds within day
- ns = secs*1e9 + int64(t.Nanosecond())
- return
- }
- func decodeChar(col collation, buf []byte) string {
- return charset2utf8(col, buf)
- }
- func decodeUcs2(buf []byte) string {
- res, err := ucs22str(buf)
- if err != nil {
- badStreamPanicf("Invalid UCS2 encoding: %s", err.Error())
- }
- return res
- }
- func decodeNChar(buf []byte) string {
- return decodeUcs2(buf)
- }
- func decodeXml(ti typeInfo, buf []byte) string {
- return decodeUcs2(buf)
- }
- func decodeUdt(ti typeInfo, buf []byte) int {
- panic("Not implemented")
- }
- // makes go/sql type instance as described below
- // It should return
- // the value type that can be used to scan types into. For example, the database
- // column type "bigint" this should return "reflect.TypeOf(int64(0))".
- func makeGoLangScanType(ti typeInfo) reflect.Type {
- switch ti.TypeId {
- case typeInt4:
- return reflect.TypeOf(int64(0))
- case typeInt8:
- return reflect.TypeOf(int64(0))
- case typeFlt4:
- return reflect.TypeOf(float64(0))
- case typeIntN:
- switch ti.Size {
- case 1:
- return reflect.TypeOf(int64(0))
- case 2:
- return reflect.TypeOf(int64(0))
- case 4:
- return reflect.TypeOf(int64(0))
- case 8:
- return reflect.TypeOf(int64(0))
- default:
- panic("invalid size of INTNTYPE")
- }
- case typeFlt8:
- return reflect.TypeOf(float64(0))
- case typeFltN:
- switch ti.Size {
- case 4:
- return reflect.TypeOf(float64(0))
- case 8:
- return reflect.TypeOf(float64(0))
- default:
- panic("invalid size of FLNNTYPE")
- }
- case typeBigVarBin:
- return reflect.TypeOf([]byte{})
- case typeVarChar:
- return reflect.TypeOf("")
- case typeNVarChar:
- return reflect.TypeOf("")
- case typeBit, typeBitN:
- return reflect.TypeOf(true)
- case typeDecimalN, typeNumericN:
- return reflect.TypeOf([]byte{})
- case typeMoneyN:
- switch ti.Size {
- case 4:
- return reflect.TypeOf([]byte{})
- case 8:
- return reflect.TypeOf([]byte{})
- default:
- panic("invalid size of MONEYN")
- }
- case typeDateTimeN:
- switch ti.Size {
- case 4:
- return reflect.TypeOf(time.Time{})
- case 8:
- return reflect.TypeOf(time.Time{})
- default:
- panic("invalid size of DATETIMEN")
- }
- case typeDateTime2N:
- return reflect.TypeOf(time.Time{})
- case typeDateN:
- return reflect.TypeOf(time.Time{})
- case typeTimeN:
- return reflect.TypeOf(time.Time{})
- case typeDateTimeOffsetN:
- return reflect.TypeOf(time.Time{})
- case typeBigVarChar:
- return reflect.TypeOf("")
- case typeBigChar:
- return reflect.TypeOf("")
- case typeNChar:
- return reflect.TypeOf("")
- case typeGuid:
- return reflect.TypeOf([]byte{})
- case typeXml:
- return reflect.TypeOf("")
- case typeText:
- return reflect.TypeOf("")
- case typeNText:
- return reflect.TypeOf("")
- case typeImage:
- return reflect.TypeOf([]byte{})
- case typeVariant:
- return reflect.TypeOf(nil)
- default:
- panic(fmt.Sprintf("not implemented makeDecl for type %d", ti.TypeId))
- }
- }
- func makeDecl(ti typeInfo) string {
- switch ti.TypeId {
- case typeInt8:
- return "bigint"
- case typeFlt4:
- return "real"
- case typeIntN:
- switch ti.Size {
- case 1:
- return "tinyint"
- case 2:
- return "smallint"
- case 4:
- return "int"
- case 8:
- return "bigint"
- default:
- panic("invalid size of INTNTYPE")
- }
- case typeFlt8:
- return "float"
- case typeFltN:
- switch ti.Size {
- case 4:
- return "real"
- case 8:
- return "float"
- default:
- panic("invalid size of FLNNTYPE")
- }
- case typeBigVarBin:
- if ti.Size > 8000 || ti.Size == 0 {
- return "varbinary(max)"
- } else {
- return fmt.Sprintf("varbinary(%d)", ti.Size)
- }
- case typeNVarChar:
- if ti.Size > 8000 || ti.Size == 0 {
- return "nvarchar(max)"
- } else {
- return fmt.Sprintf("nvarchar(%d)", ti.Size/2)
- }
- case typeBit, typeBitN:
- return "bit"
- case typeDateTimeN:
- return "datetime"
- case typeDateTimeOffsetN:
- return fmt.Sprintf("datetimeoffset(%d)", ti.Scale)
- default:
- panic(fmt.Sprintf("not implemented makeDecl for type %d", ti.TypeId))
- }
- }
- // makes go/sql type name as described below
- // RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the
- // database system type name without the length. Type names should be uppercase.
- // Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT",
- // "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML",
- // "TIMESTAMP".
- func makeGoLangTypeName(ti typeInfo) string {
- switch ti.TypeId {
- case typeInt4:
- return "INT"
- case typeInt8:
- return "BIGINT"
- case typeFlt4:
- return "REAL"
- case typeIntN:
- switch ti.Size {
- case 1:
- return "TINYINT"
- case 2:
- return "SMALLINT"
- case 4:
- return "INT"
- case 8:
- return "BIGINT"
- default:
- panic("invalid size of INTNTYPE")
- }
- case typeFlt8:
- return "FLOAT"
- case typeFltN:
- switch ti.Size {
- case 4:
- return "REAL"
- case 8:
- return "FLOAT"
- default:
- panic("invalid size of FLNNTYPE")
- }
- case typeBigVarBin:
- return "VARBINARY"
- case typeVarChar:
- return "VARCHAR"
- case typeNVarChar:
- return "NVARCHAR"
- case typeBit, typeBitN:
- return "BIT"
- case typeDecimalN, typeNumericN:
- return "DECIMAL"
- case typeMoneyN:
- switch ti.Size {
- case 4:
- return "SMALLMONEY"
- case 8:
- return "MONEY"
- default:
- panic("invalid size of MONEYN")
- }
- case typeDateTimeN:
- switch ti.Size {
- case 4:
- return "SMALLDATETIME"
- case 8:
- return "DATETIME"
- default:
- panic("invalid size of DATETIMEN")
- }
- case typeDateTime2N:
- return "DATETIME2"
- case typeDateN:
- return "DATE"
- case typeTimeN:
- return "TIME"
- case typeDateTimeOffsetN:
- return "DATETIMEOFFSET"
- case typeBigVarChar:
- return "VARCHAR"
- case typeBigChar:
- return "CHAR"
- case typeNChar:
- return "NCHAR"
- case typeGuid:
- return "UNIQUEIDENTIFIER"
- case typeXml:
- return "XML"
- case typeText:
- return "TEXT"
- case typeNText:
- return "NTEXT"
- case typeImage:
- return "IMAGE"
- case typeVariant:
- return "SQL_VARIANT"
- default:
- panic(fmt.Sprintf("not implemented makeDecl for type %d", ti.TypeId))
- }
- }
- // makes go/sql type length as described below
- // It should return the length
- // of the column type if the column is a variable length type. If the column is
- // not a variable length type ok should return false.
- // If length is not limited other than system limits, it should return math.MaxInt64.
- // The following are examples of returned values for various types:
- // TEXT (math.MaxInt64, true)
- // varchar(10) (10, true)
- // nvarchar(10) (10, true)
- // decimal (0, false)
- // int (0, false)
- // bytea(30) (30, true)
- func makeGoLangTypeLength(ti typeInfo) (int64, bool) {
- switch ti.TypeId {
- case typeInt4:
- return 0, false
- case typeInt8:
- return 0, false
- case typeFlt4:
- return 0, false
- case typeIntN:
- switch ti.Size {
- case 1:
- return 0, false
- case 2:
- return 0, false
- case 4:
- return 0, false
- case 8:
- return 0, false
- default:
- panic("invalid size of INTNTYPE")
- }
- case typeFlt8:
- return 0, false
- case typeFltN:
- switch ti.Size {
- case 4:
- return 0, false
- case 8:
- return 0, false
- default:
- panic("invalid size of FLNNTYPE")
- }
- case typeBit, typeBitN:
- return 0, false
- case typeDecimalN, typeNumericN:
- return 0, false
- case typeMoneyN:
- switch ti.Size {
- case 4:
- return 0, false
- case 8:
- return 0, false
- default:
- panic("invalid size of MONEYN")
- }
- case typeDateTimeN:
- switch ti.Size {
- case 4:
- return 0, false
- case 8:
- return 0, false
- default:
- panic("invalid size of DATETIMEN")
- }
- case typeDateTime2N:
- return 0, false
- case typeDateN:
- return 0, false
- case typeTimeN:
- return 0, false
- case typeDateTimeOffsetN:
- return 0, false
- case typeBigVarBin:
- if ti.Size == 0xffff {
- return 2147483645, true
- } else {
- return int64(ti.Size), true
- }
- case typeVarChar:
- return int64(ti.Size), true
- case typeBigVarChar:
- if ti.Size == 0xffff {
- return 2147483645, true
- } else {
- return int64(ti.Size), true
- }
- case typeBigChar:
- return int64(ti.Size), true
- case typeNVarChar:
- if ti.Size == 0xffff {
- return 2147483645 / 2, true
- } else {
- return int64(ti.Size) / 2, true
- }
- case typeNChar:
- return int64(ti.Size) / 2, true
- case typeGuid:
- return 0, false
- case typeXml:
- return 1073741822, true
- case typeText:
- return 2147483647, true
- case typeNText:
- return 1073741823, true
- case typeImage:
- return 2147483647, true
- case typeVariant:
- return 0, false
- default:
- panic(fmt.Sprintf("not implemented makeDecl for type %d", ti.TypeId))
- }
- }
- // makes go/sql type precision and scale as described below
- // It should return the length
- // of the column type if the column is a variable length type. If the column is
- // not a variable length type ok should return false.
- // If length is not limited other than system limits, it should return math.MaxInt64.
- // The following are examples of returned values for various types:
- // TEXT (math.MaxInt64, true)
- // varchar(10) (10, true)
- // nvarchar(10) (10, true)
- // decimal (0, false)
- // int (0, false)
- // bytea(30) (30, true)
- func makeGoLangTypePrecisionScale(ti typeInfo) (int64, int64, bool) {
- switch ti.TypeId {
- case typeInt4:
- return 0, 0, false
- case typeInt8:
- return 0, 0, false
- case typeFlt4:
- return 0, 0, false
- case typeIntN:
- switch ti.Size {
- case 1:
- return 0, 0, false
- case 2:
- return 0, 0, false
- case 4:
- return 0, 0, false
- case 8:
- return 0, 0, false
- default:
- panic("invalid size of INTNTYPE")
- }
- case typeFlt8:
- return 0, 0, false
- case typeFltN:
- switch ti.Size {
- case 4:
- return 0, 0, false
- case 8:
- return 0, 0, false
- default:
- panic("invalid size of FLNNTYPE")
- }
- case typeBit, typeBitN:
- return 0, 0, false
- case typeDecimalN, typeNumericN:
- return int64(ti.Prec), int64(ti.Scale), true
- case typeMoneyN:
- switch ti.Size {
- case 4:
- return 0, 0, false
- case 8:
- return 0, 0, false
- default:
- panic("invalid size of MONEYN")
- }
- case typeDateTimeN:
- switch ti.Size {
- case 4:
- return 0, 0, false
- case 8:
- return 0, 0, false
- default:
- panic("invalid size of DATETIMEN")
- }
- case typeDateTime2N:
- return 0, 0, false
- case typeDateN:
- return 0, 0, false
- case typeTimeN:
- return 0, 0, false
- case typeDateTimeOffsetN:
- return 0, 0, false
- case typeBigVarBin:
- return 0, 0, false
- case typeVarChar:
- return 0, 0, false
- case typeBigVarChar:
- return 0, 0, false
- case typeBigChar:
- return 0, 0, false
- case typeNVarChar:
- return 0, 0, false
- case typeNChar:
- return 0, 0, false
- case typeGuid:
- return 0, 0, false
- case typeXml:
- return 0, 0, false
- case typeText:
- return 0, 0, false
- case typeNText:
- return 0, 0, false
- case typeImage:
- return 0, 0, false
- case typeVariant:
- return 0, 0, false
- default:
- panic(fmt.Sprintf("not implemented makeDecl for type %d", ti.TypeId))
- }
- }
|