12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580 |
- package mssql
-
- import (
- "bytes"
- "encoding/binary"
- "fmt"
- "io"
- "math"
- "reflect"
- "strconv"
- "time"
-
- "github.com/denisenkom/go-mssqldb/internal/cp"
- )
-
- // 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
- typeTvp = 0xf3
-
- // long length types
- typeText = 0x23
- typeImage = 0x22
- typeNText = 0x63
- typeVariant = 0x62
- )
- const _PLP_NULL = 0xFFFFFFFFFFFFFFFF
- const _UNKNOWN_PLP_LEN = 0xFFFFFFFFFFFFFFFE
- const _PLP_TERMINATOR = 0x00000000
-
- // TVP COLUMN FLAGS
- const _TVP_END_TOKEN = 0x00
- const _TVP_ROW_TOKEN = 0x01
-
- // 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 cp.Collation
- UdtInfo udtInfo
- XmlInfo xmlInfo
- Reader func(ti *typeInfo, r *tdsBuffer) (res interface{})
- Writer func(w io.Writer, ti typeInfo, buf []byte) (err error)
- }
-
- // Common Language Runtime (CLR) Instances
- // http://msdn.microsoft.com/en-us/library/dd357962.aspx
- type udtInfo struct {
- //MaxByteSize uint32
- DBName string
- SchemaName string
- TypeName string
- AssemblyQualifiedName string
- }
-
- // XML Values
- // http://msdn.microsoft.com/en-us/library/dd304764.aspx
- type xmlInfo struct {
- SchemaPresent uint8
- DBName string
- OwningSchema string
- XmlSchemaCollection string
- }
-
- 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
- }
-
- // https://msdn.microsoft.com/en-us/library/dd358284.aspx
- 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
- // https://msdn.microsoft.com/en-us/library/dd341171.aspx
- ti.Writer = writeFixedType
- case typeTvp:
- ti.Writer = writeFixedType
- default: // all others are VARLENTYPE
- err = writeVarLen(w, ti)
- if err != nil {
- return
- }
- }
- return
- }
-
- func writeFixedType(w io.Writer, ti typeInfo, buf []byte) (err error) {
- _, err = w.Write(buf)
- return
- }
-
- // https://msdn.microsoft.com/en-us/library/dd358341.aspx
- func writeVarLen(w io.Writer, ti *typeInfo) (err error) {
- switch ti.TypeId {
-
- case typeDateN:
- ti.Writer = writeByteLenType
- 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:
- if err = binary.Write(w, binary.LittleEndian, ti.XmlInfo.SchemaPresent); err != nil {
- return
- }
- }
- case typeText, typeImage, typeNText, typeVariant:
- // LONGLEN_TYPE
- if err = binary.Write(w, binary.LittleEndian, uint32(ti.Size)); err != nil {
- return
- }
- if err = writeCollation(w, ti.Collation); err != nil {
- return
- }
- ti.Writer = writeLongLenType
- 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 encodeDateTim4(val time.Time) (buf []byte) {
- buf = make([]byte, 4)
-
- ref := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)
- dur := val.Sub(ref)
- days := dur / (24 * time.Hour)
- mins := val.Hour()*60 + val.Minute()
- if days < 0 {
- days = 0
- mins = 0
- }
-
- binary.LittleEndian.PutUint16(buf[:2], uint16(days))
- binary.LittleEndian.PutUint16(buf[2:], uint16(mins))
- return
- }
-
- // encodes datetime value
- // type identifier is typeDateTimeN
- func encodeDateTime(t time.Time) (res []byte) {
- // base date in days since Jan 1st 1900
- basedays := gregorianDays(1900, 1)
- // days since Jan 1st 1900 (same TZ as t)
- days := gregorianDays(t.Year(), t.YearDay()) - basedays
- tm := 300*(t.Second()+t.Minute()*60+t.Hour()*60*60) + t.Nanosecond()*300/1e9
- // minimum and maximum possible
- mindays := gregorianDays(1753, 1) - basedays
- maxdays := gregorianDays(9999, 365) - basedays
- if days < mindays {
- days = mindays
- tm = 0
- }
- if days > maxdays {
- days = maxdays
- tm = (23*60*60+59*60+59)*300 + 299
- }
- res = make([]byte, 8)
- binary.LittleEndian.PutUint32(res[0:4], uint32(days))
- binary.LittleEndian.PutUint32(res[4:8], uint32(tm))
- return
- }
-
- 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: %d", len(buf))
- }
- 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 typeDateTim4:
- return decodeDateTim4(buf)
- case typeDateTime:
- return decodeDateTime(buf)
- 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(len(buf)))
- 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")
- }
- func writeLongLenType(w io.Writer, ti typeInfo, buf []byte) (err error) {
- //textptr
- err = binary.Write(w, binary.LittleEndian, byte(0x10))
- if err != nil {
- return
- }
- err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF))
- if err != nil {
- return
- }
- err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF))
- if err != nil {
- return
- }
- //timestamp?
- err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF))
- if err != nil {
- return
- }
-
- err = binary.Write(w, binary.LittleEndian, uint32(ti.Size))
- if err != nil {
- return
- }
- _, err = w.Write(buf)
- return
- }
-
- func readCollation(r *tdsBuffer) (res cp.Collation) {
- res.LcidAndFlags = r.uint32()
- res.SortId = r.byte()
- return
- }
-
- func writeCollation(w io.Writer, col cp.Collation) (err error) {
- if err = binary.Write(w, binary.LittleEndian, col.LcidAndFlags); err != nil {
- return
- }
- err = binary.Write(w, binary.LittleEndian, col.SortId)
- return
- }
-
- // 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 _PLP_NULL:
- // null
- return nil
- case _UNKNOWN_PLP_LEN:
- // 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(_UNKNOWN_PLP_LEN)); err != nil {
- return
- }
- for {
- chunksize := uint32(len(buf))
- if chunksize == 0 {
- err = binary.Write(w, binary.LittleEndian, uint32(_PLP_TERMINATOR))
- return
- }
- if err = binary.Write(w, binary.LittleEndian, chunksize); err != nil {
- 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:
- ti.XmlInfo.SchemaPresent = r.byte()
- if ti.XmlInfo.SchemaPresent != 0 {
- // dbname
- ti.XmlInfo.DBName = r.BVarChar()
- // owning schema
- ti.XmlInfo.OwningSchema = r.BVarChar()
- // xml schema collection
- ti.XmlInfo.XmlSchemaCollection = r.UsVarChar()
- }
- ti.Reader = readPLPType
- case typeUdt:
- ti.Size = int(r.uint16())
- ti.UdtInfo.DBName = r.BVarChar()
- ti.UdtInfo.SchemaName = r.BVarChar()
- ti.UdtInfo.TypeName = r.BVarChar()
- ti.UdtInfo.AssemblyQualifiedName = r.UsVarChar()
-
- ti.Buffer = make([]byte, ti.Size)
- ti.Reader = readPLPType
- case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar,
- typeNVarChar, typeNChar:
- // 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 encodeDate(val time.Time) (buf []byte) {
- days, _, _ := dateTime2(val)
- buf = make([]byte, 3)
- buf[0] = byte(days)
- buf[1] = byte(days >> 8)
- buf[2] = byte(days >> 16)
- return
- }
-
- 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
- }
-
- // calculate size of time field in bytes
- func calcTimeSize(scale int) int {
- if scale <= 2 {
- return 3
- } else if scale <= 4 {
- return 4
- } else {
- return 5
- }
- }
-
- // writes time value into a field buffer
- // buffer should be at least calcTimeSize long
- func encodeTimeInt(seconds, ns, scale int, buf []byte) {
- ns_total := int64(seconds)*1000*1000*1000 + int64(ns)
- t := ns_total / int64(math.Pow10(int(scale)*-1)*1e9)
- buf[0] = byte(t)
- buf[1] = byte(t >> 8)
- buf[2] = byte(t >> 16)
- buf[3] = byte(t >> 24)
- buf[4] = byte(t >> 32)
- }
-
- 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 encodeTime(hour, minute, second, ns, scale int) (buf []byte) {
- seconds := hour*3600 + minute*60 + second
- buf = make([]byte, calcTimeSize(scale))
- encodeTimeInt(seconds, ns, scale, buf)
- return
- }
-
- 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 encodeDateTime2(val time.Time, scale int) (buf []byte) {
- days, seconds, ns := dateTime2(val)
- timesize := calcTimeSize(scale)
- buf = make([]byte, 3+timesize)
- encodeTimeInt(seconds, ns, scale, buf)
- buf[timesize] = byte(days)
- buf[timesize+1] = byte(days >> 8)
- buf[timesize+2] = byte(days >> 16)
- return
- }
-
- 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 encodeDateTimeOffset(val time.Time, scale int) (buf []byte) {
- timesize := calcTimeSize(scale)
- buf = make([]byte, timesize+2+3)
- days, seconds, ns := dateTime2(val.In(time.UTC))
- encodeTimeInt(seconds, ns, scale, buf)
- buf[timesize] = byte(days)
- buf[timesize+1] = byte(days >> 8)
- buf[timesize+2] = byte(days >> 16)
- _, offset := val.Zone()
- offset /= 60
- buf[timesize+3] = byte(offset)
- buf[timesize+4] = byte(offset >> 8)
- return
- }
-
- // returns days since Jan 1st 0001 in Gregorian calendar
- func gregorianDays(year, yearday int) int {
- year0 := year - 1
- return year0*365 + year0/4 - year0/100 + year0/400 + yearday - 1
- }
-
- func dateTime2(t time.Time) (days int, seconds int, ns int) {
- // days since Jan 1 1 (in same TZ as t)
- days = gregorianDays(t.Year(), t.YearDay())
- seconds = t.Second() + t.Minute()*60 + t.Hour()*60*60
- ns = t.Nanosecond()
- if days < 0 {
- days = 0
- seconds = 0
- ns = 0
- }
- max := gregorianDays(9999, 365)
- if days > max {
- days = max
- seconds = 59 + 59*60 + 23*60*60
- ns = 999999900
- }
- return
- }
-
- func decodeChar(col cp.Collation, buf []byte) string {
- return cp.CharsetToUTF8(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) []byte {
- return buf
- }
-
- // 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 typeInt1:
- return reflect.TypeOf(int64(0))
- case typeInt2:
- return reflect.TypeOf(int64(0))
- 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 typeMoney, typeMoney4, typeMoneyN:
- switch ti.Size {
- case 4:
- return reflect.TypeOf([]byte{})
- case 8:
- return reflect.TypeOf([]byte{})
- default:
- panic("invalid size of MONEYN")
- }
- case typeDateTim4:
- return reflect.TypeOf(time.Time{})
- case typeDateTime:
- return reflect.TypeOf(time.Time{})
- 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 typeBigBinary:
- return reflect.TypeOf([]byte{})
- case typeVariant:
- return reflect.TypeOf(nil)
- default:
- panic(fmt.Sprintf("not implemented makeGoLangScanType for type %d", ti.TypeId))
- }
- }
-
- func makeDecl(ti typeInfo) string {
- switch ti.TypeId {
- case typeNull:
- // maybe we should use something else here
- // this is tested in TestNull
- return "nvarchar(1)"
- case typeInt1:
- return "tinyint"
- case typeBigBinary:
- return fmt.Sprintf("binary(%d)", ti.Size)
- case typeInt2:
- return "smallint"
- 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 typeDecimal, typeDecimalN:
- return fmt.Sprintf("decimal(%d, %d)", ti.Prec, ti.Scale)
- case typeNumeric, typeNumericN:
- return fmt.Sprintf("numeric(%d, %d)", ti.Prec, ti.Scale)
- case typeMoney4:
- return "smallmoney"
- case typeMoney:
- return "money"
- case typeMoneyN:
- switch ti.Size {
- case 4:
- return "smallmoney"
- case 8:
- return "money"
- default:
- panic("invalid size of MONEYNTYPE")
- }
- case typeBigVarBin:
- if ti.Size > 8000 || ti.Size == 0 {
- return "varbinary(max)"
- } else {
- return fmt.Sprintf("varbinary(%d)", ti.Size)
- }
- case typeNChar:
- return fmt.Sprintf("nchar(%d)", ti.Size/2)
- case typeBigChar, typeChar:
- return fmt.Sprintf("char(%d)", ti.Size)
- case typeBigVarChar, typeVarChar:
- if ti.Size > 4000 || ti.Size == 0 {
- return fmt.Sprintf("varchar(max)")
- } else {
- return fmt.Sprintf("varchar(%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 typeDateN:
- return "date"
- case typeDateTim4:
- return "smalldatetime"
- case typeDateTime:
- return "datetime"
- case typeDateTimeN:
- switch ti.Size {
- case 4:
- return "smalldatetime"
- case 8:
- return "datetime"
- default:
- panic("invalid size of DATETIMNTYPE")
- }
- case typeTimeN:
- return "time"
- case typeDateTime2N:
- return fmt.Sprintf("datetime2(%d)", ti.Scale)
- case typeDateTimeOffsetN:
- return fmt.Sprintf("datetimeoffset(%d)", ti.Scale)
- case typeText:
- return "text"
- case typeNText:
- return "ntext"
- case typeUdt:
- return ti.UdtInfo.TypeName
- case typeGuid:
- return "uniqueidentifier"
- case typeTvp:
- if ti.UdtInfo.SchemaName != "" {
- return fmt.Sprintf("%s.%s READONLY", ti.UdtInfo.SchemaName, ti.UdtInfo.TypeName)
- }
- return fmt.Sprintf("%s READONLY", ti.UdtInfo.TypeName)
- default:
- panic(fmt.Sprintf("not implemented makeDecl for type %#x", 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 typeInt1:
- return "TINYINT"
- case typeInt2:
- return "SMALLINT"
- 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 typeMoney, typeMoney4, typeMoneyN:
- switch ti.Size {
- case 4:
- return "SMALLMONEY"
- case 8:
- return "MONEY"
- default:
- panic("invalid size of MONEYN")
- }
- case typeDateTim4:
- return "SMALLDATETIME"
- case typeDateTime:
- return "DATETIME"
- 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"
- case typeBigBinary:
- return "BINARY"
- default:
- panic(fmt.Sprintf("not implemented makeGoLangTypeName 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 typeInt1:
- return 0, false
- case typeInt2:
- return 0, false
- 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 typeMoney, typeMoney4, typeMoneyN:
- switch ti.Size {
- case 4:
- return 0, false
- case 8:
- return 0, false
- default:
- panic("invalid size of MONEYN")
- }
- case typeDateTim4, typeDateTime:
- return 0, false
- 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
- case typeBigBinary:
- return 0, false
- default:
- panic(fmt.Sprintf("not implemented makeGoLangTypeLength 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 typeInt1:
- return 0, 0, false
- case typeInt2:
- return 0, 0, false
- 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 typeMoney, typeMoney4, typeMoneyN:
- switch ti.Size {
- case 4:
- return 0, 0, false
- case 8:
- return 0, 0, false
- default:
- panic("invalid size of MONEYN")
- }
- case typeDateTim4, typeDateTime:
- return 0, 0, false
- 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
- case typeBigBinary:
- return 0, 0, false
- default:
- panic(fmt.Sprintf("not implemented makeGoLangTypePrecisionScale for type %d", ti.TypeId))
- }
- }
|