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