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