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 true {
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 err = binary.Write(w, binary.LittleEndian, uint64(_UNKNOWN_PLP_LEN)); err != nil {
694		return
695	}
696	for {
697		chunksize := uint32(len(buf))
698		if chunksize == 0 {
699			err = binary.Write(w, binary.LittleEndian, uint32(_PLP_TERMINATOR))
700			return
701		}
702		if err = binary.Write(w, binary.LittleEndian, chunksize); err != nil {
703			return
704		}
705		if _, err = w.Write(buf[:chunksize]); err != nil {
706			return
707		}
708		buf = buf[chunksize:]
709	}
710}
711
712func readVarLen(ti *typeInfo, r *tdsBuffer) {
713	switch ti.TypeId {
714	case typeDateN:
715		ti.Size = 3
716		ti.Reader = readByteLenType
717		ti.Buffer = make([]byte, ti.Size)
718	case typeTimeN, typeDateTime2N, typeDateTimeOffsetN:
719		ti.Scale = r.byte()
720		switch ti.Scale {
721		case 0, 1, 2:
722			ti.Size = 3
723		case 3, 4:
724			ti.Size = 4
725		case 5, 6, 7:
726			ti.Size = 5
727		default:
728			badStreamPanicf("Invalid scale for TIME/DATETIME2/DATETIMEOFFSET type")
729		}
730		switch ti.TypeId {
731		case typeDateTime2N:
732			ti.Size += 3
733		case typeDateTimeOffsetN:
734			ti.Size += 5
735		}
736		ti.Reader = readByteLenType
737		ti.Buffer = make([]byte, ti.Size)
738	case typeGuid, typeIntN, typeDecimal, typeNumeric,
739		typeBitN, typeDecimalN, typeNumericN, typeFltN,
740		typeMoneyN, typeDateTimeN, typeChar,
741		typeVarChar, typeBinary, typeVarBinary:
742		// byle len types
743		ti.Size = int(r.byte())
744		ti.Buffer = make([]byte, ti.Size)
745		switch ti.TypeId {
746		case typeDecimal, typeNumeric, typeDecimalN, typeNumericN:
747			ti.Prec = r.byte()
748			ti.Scale = r.byte()
749		}
750		ti.Reader = readByteLenType
751	case typeXml:
752		ti.XmlInfo.SchemaPresent = r.byte()
753		if ti.XmlInfo.SchemaPresent != 0 {
754			// dbname
755			ti.XmlInfo.DBName = r.BVarChar()
756			// owning schema
757			ti.XmlInfo.OwningSchema = r.BVarChar()
758			// xml schema collection
759			ti.XmlInfo.XmlSchemaCollection = r.UsVarChar()
760		}
761		ti.Reader = readPLPType
762	case typeUdt:
763		ti.Size = int(r.uint16())
764		ti.UdtInfo.DBName = r.BVarChar()
765		ti.UdtInfo.SchemaName = r.BVarChar()
766		ti.UdtInfo.TypeName = r.BVarChar()
767		ti.UdtInfo.AssemblyQualifiedName = r.UsVarChar()
768
769		ti.Buffer = make([]byte, ti.Size)
770		ti.Reader = readPLPType
771	case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar,
772		typeNVarChar, typeNChar:
773		// short len types
774		ti.Size = int(r.uint16())
775		switch ti.TypeId {
776		case typeBigVarChar, typeBigChar, typeNVarChar, typeNChar:
777			ti.Collation = readCollation(r)
778		}
779		if ti.Size == 0xffff {
780			ti.Reader = readPLPType
781		} else {
782			ti.Buffer = make([]byte, ti.Size)
783			ti.Reader = readShortLenType
784		}
785	case typeText, typeImage, typeNText, typeVariant:
786		// LONGLEN_TYPE
787		ti.Size = int(r.int32())
788		switch ti.TypeId {
789		case typeText, typeNText:
790			ti.Collation = readCollation(r)
791			// ignore tablenames
792			numparts := int(r.byte())
793			for i := 0; i < numparts; i++ {
794				r.UsVarChar()
795			}
796			ti.Reader = readLongLenType
797		case typeImage:
798			// ignore tablenames
799			numparts := int(r.byte())
800			for i := 0; i < numparts; i++ {
801				r.UsVarChar()
802			}
803			ti.Reader = readLongLenType
804		case typeVariant:
805			ti.Reader = readVariantType
806		}
807	default:
808		badStreamPanicf("Invalid type %d", ti.TypeId)
809	}
810	return
811}
812
813func decodeMoney(buf []byte) []byte {
814	money := int64(uint64(buf[4]) |
815		uint64(buf[5])<<8 |
816		uint64(buf[6])<<16 |
817		uint64(buf[7])<<24 |
818		uint64(buf[0])<<32 |
819		uint64(buf[1])<<40 |
820		uint64(buf[2])<<48 |
821		uint64(buf[3])<<56)
822	return decimal.ScaleBytes(strconv.FormatInt(money, 10), 4)
823}
824
825func decodeMoney4(buf []byte) []byte {
826	money := int32(binary.LittleEndian.Uint32(buf[0:4]))
827	return decimal.ScaleBytes(strconv.FormatInt(int64(money), 10), 4)
828}
829
830func decodeGuid(buf []byte) []byte {
831	res := make([]byte, 16)
832	copy(res, buf)
833	return res
834}
835
836func decodeDecimal(prec uint8, scale uint8, buf []byte) []byte {
837	var sign uint8
838	sign = buf[0]
839	var dec decimal.Decimal
840	dec.SetPositive(sign != 0)
841	dec.SetPrec(prec)
842	dec.SetScale(scale)
843	buf = buf[1:]
844	l := len(buf) / 4
845	for i := 0; i < l; i++ {
846		dec.SetInteger(binary.LittleEndian.Uint32(buf[0:4]), uint8(i))
847		buf = buf[4:]
848	}
849	return dec.Bytes()
850}
851
852// http://msdn.microsoft.com/en-us/library/ee780895.aspx
853func decodeDateInt(buf []byte) (days int) {
854	days = int(buf[0]) + int(buf[1])*256 + int(buf[2])*256*256
855	return
856}
857
858func decodeDate(buf []byte) time.Time {
859	return time.Date(1, 1, 1+decodeDateInt(buf), 0, 0, 0, 0, time.UTC)
860}
861
862func encodeDate(val time.Time) (buf []byte) {
863	days, _, _ := dateTime2(val)
864	buf = make([]byte, 3)
865	buf[0] = byte(days)
866	buf[1] = byte(days >> 8)
867	buf[2] = byte(days >> 16)
868	return
869}
870
871func decodeTimeInt(scale uint8, buf []byte) (sec int, ns int) {
872	var acc uint64 = 0
873	for i := len(buf) - 1; i >= 0; i-- {
874		acc <<= 8
875		acc |= uint64(buf[i])
876	}
877	for i := 0; i < 7-int(scale); i++ {
878		acc *= 10
879	}
880	nsbig := acc * 100
881	sec = int(nsbig / 1000000000)
882	ns = int(nsbig % 1000000000)
883	return
884}
885
886// calculate size of time field in bytes
887func calcTimeSize(scale int) int {
888	if scale <= 2 {
889		return 3
890	} else if scale <= 4 {
891		return 4
892	} else {
893		return 5
894	}
895}
896
897// writes time value into a field buffer
898// buffer should be at least calcTimeSize long
899func encodeTimeInt(seconds, ns, scale int, buf []byte) {
900	ns_total := int64(seconds)*1000*1000*1000 + int64(ns)
901	t := ns_total / int64(math.Pow10(int(scale)*-1)*1e9)
902	buf[0] = byte(t)
903	buf[1] = byte(t >> 8)
904	buf[2] = byte(t >> 16)
905	buf[3] = byte(t >> 24)
906	buf[4] = byte(t >> 32)
907}
908
909func decodeTime(scale uint8, buf []byte) time.Time {
910	sec, ns := decodeTimeInt(scale, buf)
911	return time.Date(1, 1, 1, 0, 0, sec, ns, time.UTC)
912}
913
914func encodeTime(hour, minute, second, ns, scale int) (buf []byte) {
915	seconds := hour*3600 + minute*60 + second
916	buf = make([]byte, calcTimeSize(scale))
917	encodeTimeInt(seconds, ns, scale, buf)
918	return
919}
920
921func decodeDateTime2(scale uint8, buf []byte) time.Time {
922	timesize := len(buf) - 3
923	sec, ns := decodeTimeInt(scale, buf[:timesize])
924	days := decodeDateInt(buf[timesize:])
925	return time.Date(1, 1, 1+days, 0, 0, sec, ns, time.UTC)
926}
927
928func encodeDateTime2(val time.Time, scale int) (buf []byte) {
929	days, seconds, ns := dateTime2(val)
930	timesize := calcTimeSize(scale)
931	buf = make([]byte, 3+timesize)
932	encodeTimeInt(seconds, ns, scale, buf)
933	buf[timesize] = byte(days)
934	buf[timesize+1] = byte(days >> 8)
935	buf[timesize+2] = byte(days >> 16)
936	return
937}
938
939func decodeDateTimeOffset(scale uint8, buf []byte) time.Time {
940	timesize := len(buf) - 3 - 2
941	sec, ns := decodeTimeInt(scale, buf[:timesize])
942	buf = buf[timesize:]
943	days := decodeDateInt(buf[:3])
944	buf = buf[3:]
945	offset := int(int16(binary.LittleEndian.Uint16(buf))) // in mins
946	return time.Date(1, 1, 1+days, 0, 0, sec+offset*60, ns,
947		time.FixedZone("", offset*60))
948}
949
950func encodeDateTimeOffset(val time.Time, scale int) (buf []byte) {
951	timesize := calcTimeSize(scale)
952	buf = make([]byte, timesize+2+3)
953	days, seconds, ns := dateTime2(val.In(time.UTC))
954	encodeTimeInt(seconds, ns, scale, buf)
955	buf[timesize] = byte(days)
956	buf[timesize+1] = byte(days >> 8)
957	buf[timesize+2] = byte(days >> 16)
958	_, offset := val.Zone()
959	offset /= 60
960	buf[timesize+3] = byte(offset)
961	buf[timesize+4] = byte(offset >> 8)
962	return
963}
964
965// returns days since Jan 1st 0001 in Gregorian calendar
966func gregorianDays(year, yearday int) int {
967	year0 := year - 1
968	return year0*365 + year0/4 - year0/100 + year0/400 + yearday - 1
969}
970
971func dateTime2(t time.Time) (days int, seconds int, ns int) {
972	// days since Jan 1 1 (in same TZ as t)
973	days = gregorianDays(t.Year(), t.YearDay())
974	seconds = t.Second() + t.Minute()*60 + t.Hour()*60*60
975	ns = t.Nanosecond()
976	if days < 0 {
977		days = 0
978		seconds = 0
979		ns = 0
980	}
981	max := gregorianDays(9999, 365)
982	if days > max {
983		days = max
984		seconds = 59 + 59*60 + 23*60*60
985		ns = 999999900
986	}
987	return
988}
989
990func decodeChar(col cp.Collation, buf []byte) string {
991	return cp.CharsetToUTF8(col, buf)
992}
993
994func decodeUcs2(buf []byte) string {
995	res, err := ucs22str(buf)
996	if err != nil {
997		badStreamPanicf("Invalid UCS2 encoding: %s", err.Error())
998	}
999	return res
1000}
1001
1002func decodeNChar(buf []byte) string {
1003	return decodeUcs2(buf)
1004}
1005
1006func decodeXml(ti typeInfo, buf []byte) string {
1007	return decodeUcs2(buf)
1008}
1009
1010func decodeUdt(ti typeInfo, buf []byte) []byte {
1011	return buf
1012}
1013
1014// makes go/sql type instance as described below
1015// It should return
1016// the value type that can be used to scan types into. For example, the database
1017// column type "bigint" this should return "reflect.TypeOf(int64(0))".
1018func makeGoLangScanType(ti typeInfo) reflect.Type {
1019	switch ti.TypeId {
1020	case typeInt1:
1021		return reflect.TypeOf(int64(0))
1022	case typeInt2:
1023		return reflect.TypeOf(int64(0))
1024	case typeInt4:
1025		return reflect.TypeOf(int64(0))
1026	case typeInt8:
1027		return reflect.TypeOf(int64(0))
1028	case typeFlt4:
1029		return reflect.TypeOf(float64(0))
1030	case typeIntN:
1031		switch ti.Size {
1032		case 1:
1033			return reflect.TypeOf(int64(0))
1034		case 2:
1035			return reflect.TypeOf(int64(0))
1036		case 4:
1037			return reflect.TypeOf(int64(0))
1038		case 8:
1039			return reflect.TypeOf(int64(0))
1040		default:
1041			panic("invalid size of INTNTYPE")
1042		}
1043	case typeFlt8:
1044		return reflect.TypeOf(float64(0))
1045	case typeFltN:
1046		switch ti.Size {
1047		case 4:
1048			return reflect.TypeOf(float64(0))
1049		case 8:
1050			return reflect.TypeOf(float64(0))
1051		default:
1052			panic("invalid size of FLNNTYPE")
1053		}
1054	case typeBigVarBin:
1055		return reflect.TypeOf([]byte{})
1056	case typeVarChar:
1057		return reflect.TypeOf("")
1058	case typeNVarChar:
1059		return reflect.TypeOf("")
1060	case typeBit, typeBitN:
1061		return reflect.TypeOf(true)
1062	case typeDecimalN, typeNumericN:
1063		return reflect.TypeOf([]byte{})
1064	case typeMoney, typeMoney4, typeMoneyN:
1065		switch ti.Size {
1066		case 4:
1067			return reflect.TypeOf([]byte{})
1068		case 8:
1069			return reflect.TypeOf([]byte{})
1070		default:
1071			panic("invalid size of MONEYN")
1072		}
1073	case typeDateTim4:
1074		return reflect.TypeOf(time.Time{})
1075	case typeDateTime:
1076		return reflect.TypeOf(time.Time{})
1077	case typeDateTimeN:
1078		switch ti.Size {
1079		case 4:
1080			return reflect.TypeOf(time.Time{})
1081		case 8:
1082			return reflect.TypeOf(time.Time{})
1083		default:
1084			panic("invalid size of DATETIMEN")
1085		}
1086	case typeDateTime2N:
1087		return reflect.TypeOf(time.Time{})
1088	case typeDateN:
1089		return reflect.TypeOf(time.Time{})
1090	case typeTimeN:
1091		return reflect.TypeOf(time.Time{})
1092	case typeDateTimeOffsetN:
1093		return reflect.TypeOf(time.Time{})
1094	case typeBigVarChar:
1095		return reflect.TypeOf("")
1096	case typeBigChar:
1097		return reflect.TypeOf("")
1098	case typeNChar:
1099		return reflect.TypeOf("")
1100	case typeGuid:
1101		return reflect.TypeOf([]byte{})
1102	case typeXml:
1103		return reflect.TypeOf("")
1104	case typeText:
1105		return reflect.TypeOf("")
1106	case typeNText:
1107		return reflect.TypeOf("")
1108	case typeImage:
1109		return reflect.TypeOf([]byte{})
1110	case typeBigBinary:
1111		return reflect.TypeOf([]byte{})
1112	case typeVariant:
1113		return reflect.TypeOf(nil)
1114	default:
1115		panic(fmt.Sprintf("not implemented makeGoLangScanType for type %d", ti.TypeId))
1116	}
1117}
1118
1119func makeDecl(ti typeInfo) string {
1120	switch ti.TypeId {
1121	case typeNull:
1122		// maybe we should use something else here
1123		// this is tested in TestNull
1124		return "nvarchar(1)"
1125	case typeInt1:
1126		return "tinyint"
1127	case typeBigBinary:
1128		return fmt.Sprintf("binary(%d)", ti.Size)
1129	case typeInt2:
1130		return "smallint"
1131	case typeInt4:
1132		return "int"
1133	case typeInt8:
1134		return "bigint"
1135	case typeFlt4:
1136		return "real"
1137	case typeIntN:
1138		switch ti.Size {
1139		case 1:
1140			return "tinyint"
1141		case 2:
1142			return "smallint"
1143		case 4:
1144			return "int"
1145		case 8:
1146			return "bigint"
1147		default:
1148			panic("invalid size of INTNTYPE")
1149		}
1150	case typeFlt8:
1151		return "float"
1152	case typeFltN:
1153		switch ti.Size {
1154		case 4:
1155			return "real"
1156		case 8:
1157			return "float"
1158		default:
1159			panic("invalid size of FLNNTYPE")
1160		}
1161	case typeDecimal, typeDecimalN:
1162		return fmt.Sprintf("decimal(%d, %d)", ti.Prec, ti.Scale)
1163	case typeNumeric, typeNumericN:
1164		return fmt.Sprintf("numeric(%d, %d)", ti.Prec, ti.Scale)
1165	case typeMoney4:
1166		return "smallmoney"
1167	case typeMoney:
1168		return "money"
1169	case typeMoneyN:
1170		switch ti.Size {
1171		case 4:
1172			return "smallmoney"
1173		case 8:
1174			return "money"
1175		default:
1176			panic("invalid size of MONEYNTYPE")
1177		}
1178	case typeBigVarBin:
1179		if ti.Size > 8000 || ti.Size == 0 {
1180			return "varbinary(max)"
1181		} else {
1182			return fmt.Sprintf("varbinary(%d)", ti.Size)
1183		}
1184	case typeNChar:
1185		return fmt.Sprintf("nchar(%d)", ti.Size/2)
1186	case typeBigChar, typeChar:
1187		return fmt.Sprintf("char(%d)", ti.Size)
1188	case typeBigVarChar, typeVarChar:
1189		if ti.Size > 8000 || ti.Size == 0 {
1190			return fmt.Sprintf("varchar(max)")
1191		} else {
1192			return fmt.Sprintf("varchar(%d)", ti.Size)
1193		}
1194	case typeNVarChar:
1195		if ti.Size > 8000 || ti.Size == 0 {
1196			return "nvarchar(max)"
1197		} else {
1198			return fmt.Sprintf("nvarchar(%d)", ti.Size/2)
1199		}
1200	case typeBit, typeBitN:
1201		return "bit"
1202	case typeDateN:
1203		return "date"
1204	case typeDateTim4:
1205		return "smalldatetime"
1206	case typeDateTime:
1207		return "datetime"
1208	case typeDateTimeN:
1209		switch ti.Size {
1210		case 4:
1211			return "smalldatetime"
1212		case 8:
1213			return "datetime"
1214		default:
1215			panic("invalid size of DATETIMNTYPE")
1216		}
1217	case typeTimeN:
1218		return "time"
1219	case typeDateTime2N:
1220		return fmt.Sprintf("datetime2(%d)", ti.Scale)
1221	case typeDateTimeOffsetN:
1222		return fmt.Sprintf("datetimeoffset(%d)", ti.Scale)
1223	case typeText:
1224		return "text"
1225	case typeNText:
1226		return "ntext"
1227	case typeUdt:
1228		return ti.UdtInfo.TypeName
1229	case typeGuid:
1230		return "uniqueidentifier"
1231	case typeTvp:
1232		if ti.UdtInfo.SchemaName != "" {
1233			return fmt.Sprintf("%s.%s READONLY", ti.UdtInfo.SchemaName, ti.UdtInfo.TypeName)
1234		}
1235		return fmt.Sprintf("%s READONLY", ti.UdtInfo.TypeName)
1236	default:
1237		panic(fmt.Sprintf("not implemented makeDecl for type %#x", ti.TypeId))
1238	}
1239}
1240
1241// makes go/sql type name as described below
1242// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the
1243// database system type name without the length. Type names should be uppercase.
1244// Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT",
1245// "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML",
1246// "TIMESTAMP".
1247func makeGoLangTypeName(ti typeInfo) string {
1248	switch ti.TypeId {
1249	case typeInt1:
1250		return "TINYINT"
1251	case typeInt2:
1252		return "SMALLINT"
1253	case typeInt4:
1254		return "INT"
1255	case typeInt8:
1256		return "BIGINT"
1257	case typeFlt4:
1258		return "REAL"
1259	case typeIntN:
1260		switch ti.Size {
1261		case 1:
1262			return "TINYINT"
1263		case 2:
1264			return "SMALLINT"
1265		case 4:
1266			return "INT"
1267		case 8:
1268			return "BIGINT"
1269		default:
1270			panic("invalid size of INTNTYPE")
1271		}
1272	case typeFlt8:
1273		return "FLOAT"
1274	case typeFltN:
1275		switch ti.Size {
1276		case 4:
1277			return "REAL"
1278		case 8:
1279			return "FLOAT"
1280		default:
1281			panic("invalid size of FLNNTYPE")
1282		}
1283	case typeBigVarBin:
1284		return "VARBINARY"
1285	case typeVarChar:
1286		return "VARCHAR"
1287	case typeNVarChar:
1288		return "NVARCHAR"
1289	case typeBit, typeBitN:
1290		return "BIT"
1291	case typeDecimalN, typeNumericN:
1292		return "DECIMAL"
1293	case typeMoney, typeMoney4, typeMoneyN:
1294		switch ti.Size {
1295		case 4:
1296			return "SMALLMONEY"
1297		case 8:
1298			return "MONEY"
1299		default:
1300			panic("invalid size of MONEYN")
1301		}
1302	case typeDateTim4:
1303		return "SMALLDATETIME"
1304	case typeDateTime:
1305		return "DATETIME"
1306	case typeDateTimeN:
1307		switch ti.Size {
1308		case 4:
1309			return "SMALLDATETIME"
1310		case 8:
1311			return "DATETIME"
1312		default:
1313			panic("invalid size of DATETIMEN")
1314		}
1315	case typeDateTime2N:
1316		return "DATETIME2"
1317	case typeDateN:
1318		return "DATE"
1319	case typeTimeN:
1320		return "TIME"
1321	case typeDateTimeOffsetN:
1322		return "DATETIMEOFFSET"
1323	case typeBigVarChar:
1324		return "VARCHAR"
1325	case typeBigChar:
1326		return "CHAR"
1327	case typeNChar:
1328		return "NCHAR"
1329	case typeGuid:
1330		return "UNIQUEIDENTIFIER"
1331	case typeXml:
1332		return "XML"
1333	case typeText:
1334		return "TEXT"
1335	case typeNText:
1336		return "NTEXT"
1337	case typeImage:
1338		return "IMAGE"
1339	case typeVariant:
1340		return "SQL_VARIANT"
1341	case typeBigBinary:
1342		return "BINARY"
1343	default:
1344		panic(fmt.Sprintf("not implemented makeGoLangTypeName for type %d", ti.TypeId))
1345	}
1346}
1347
1348// makes go/sql type length as described below
1349// It should return the length
1350// of the column type if the column is a variable length type. If the column is
1351// not a variable length type ok should return false.
1352// If length is not limited other than system limits, it should return math.MaxInt64.
1353// The following are examples of returned values for various types:
1354//   TEXT          (math.MaxInt64, true)
1355//   varchar(10)   (10, true)
1356//   nvarchar(10)  (10, true)
1357//   decimal       (0, false)
1358//   int           (0, false)
1359//   bytea(30)     (30, true)
1360func makeGoLangTypeLength(ti typeInfo) (int64, bool) {
1361	switch ti.TypeId {
1362	case typeInt1:
1363		return 0, false
1364	case typeInt2:
1365		return 0, false
1366	case typeInt4:
1367		return 0, false
1368	case typeInt8:
1369		return 0, false
1370	case typeFlt4:
1371		return 0, false
1372	case typeIntN:
1373		switch ti.Size {
1374		case 1:
1375			return 0, false
1376		case 2:
1377			return 0, false
1378		case 4:
1379			return 0, false
1380		case 8:
1381			return 0, false
1382		default:
1383			panic("invalid size of INTNTYPE")
1384		}
1385	case typeFlt8:
1386		return 0, false
1387	case typeFltN:
1388		switch ti.Size {
1389		case 4:
1390			return 0, false
1391		case 8:
1392			return 0, false
1393		default:
1394			panic("invalid size of FLNNTYPE")
1395		}
1396	case typeBit, typeBitN:
1397		return 0, false
1398	case typeDecimalN, typeNumericN:
1399		return 0, false
1400	case typeMoney, typeMoney4, typeMoneyN:
1401		switch ti.Size {
1402		case 4:
1403			return 0, false
1404		case 8:
1405			return 0, false
1406		default:
1407			panic("invalid size of MONEYN")
1408		}
1409	case typeDateTim4, typeDateTime:
1410		return 0, false
1411	case typeDateTimeN:
1412		switch ti.Size {
1413		case 4:
1414			return 0, false
1415		case 8:
1416			return 0, false
1417		default:
1418			panic("invalid size of DATETIMEN")
1419		}
1420	case typeDateTime2N:
1421		return 0, false
1422	case typeDateN:
1423		return 0, false
1424	case typeTimeN:
1425		return 0, false
1426	case typeDateTimeOffsetN:
1427		return 0, false
1428	case typeBigVarBin:
1429		if ti.Size == 0xffff {
1430			return 2147483645, true
1431		} else {
1432			return int64(ti.Size), true
1433		}
1434	case typeVarChar:
1435		return int64(ti.Size), true
1436	case typeBigVarChar:
1437		if ti.Size == 0xffff {
1438			return 2147483645, true
1439		} else {
1440			return int64(ti.Size), true
1441		}
1442	case typeBigChar:
1443		return int64(ti.Size), true
1444	case typeNVarChar:
1445		if ti.Size == 0xffff {
1446			return 2147483645 / 2, true
1447		} else {
1448			return int64(ti.Size) / 2, true
1449		}
1450	case typeNChar:
1451		return int64(ti.Size) / 2, true
1452	case typeGuid:
1453		return 0, false
1454	case typeXml:
1455		return 1073741822, true
1456	case typeText:
1457		return 2147483647, true
1458	case typeNText:
1459		return 1073741823, true
1460	case typeImage:
1461		return 2147483647, true
1462	case typeVariant:
1463		return 0, false
1464	case typeBigBinary:
1465		return 0, false
1466	default:
1467		panic(fmt.Sprintf("not implemented makeGoLangTypeLength for type %d", ti.TypeId))
1468	}
1469}
1470
1471// makes go/sql type precision and scale as described below
1472// It should return the length
1473// of the column type if the column is a variable length type. If the column is
1474// not a variable length type ok should return false.
1475// If length is not limited other than system limits, it should return math.MaxInt64.
1476// The following are examples of returned values for various types:
1477//   TEXT          (math.MaxInt64, true)
1478//   varchar(10)   (10, true)
1479//   nvarchar(10)  (10, true)
1480//   decimal       (0, false)
1481//   int           (0, false)
1482//   bytea(30)     (30, true)
1483func makeGoLangTypePrecisionScale(ti typeInfo) (int64, int64, bool) {
1484	switch ti.TypeId {
1485	case typeInt1:
1486		return 0, 0, false
1487	case typeInt2:
1488		return 0, 0, false
1489	case typeInt4:
1490		return 0, 0, false
1491	case typeInt8:
1492		return 0, 0, false
1493	case typeFlt4:
1494		return 0, 0, false
1495	case typeIntN:
1496		switch ti.Size {
1497		case 1:
1498			return 0, 0, false
1499		case 2:
1500			return 0, 0, false
1501		case 4:
1502			return 0, 0, false
1503		case 8:
1504			return 0, 0, false
1505		default:
1506			panic("invalid size of INTNTYPE")
1507		}
1508	case typeFlt8:
1509		return 0, 0, false
1510	case typeFltN:
1511		switch ti.Size {
1512		case 4:
1513			return 0, 0, false
1514		case 8:
1515			return 0, 0, false
1516		default:
1517			panic("invalid size of FLNNTYPE")
1518		}
1519	case typeBit, typeBitN:
1520		return 0, 0, false
1521	case typeDecimalN, typeNumericN:
1522		return int64(ti.Prec), int64(ti.Scale), true
1523	case typeMoney, typeMoney4, typeMoneyN:
1524		switch ti.Size {
1525		case 4:
1526			return 0, 0, false
1527		case 8:
1528			return 0, 0, false
1529		default:
1530			panic("invalid size of MONEYN")
1531		}
1532	case typeDateTim4, typeDateTime:
1533		return 0, 0, false
1534	case typeDateTimeN:
1535		switch ti.Size {
1536		case 4:
1537			return 0, 0, false
1538		case 8:
1539			return 0, 0, false
1540		default:
1541			panic("invalid size of DATETIMEN")
1542		}
1543	case typeDateTime2N:
1544		return 0, 0, false
1545	case typeDateN:
1546		return 0, 0, false
1547	case typeTimeN:
1548		return 0, 0, false
1549	case typeDateTimeOffsetN:
1550		return 0, 0, false
1551	case typeBigVarBin:
1552		return 0, 0, false
1553	case typeVarChar:
1554		return 0, 0, false
1555	case typeBigVarChar:
1556		return 0, 0, false
1557	case typeBigChar:
1558		return 0, 0, false
1559	case typeNVarChar:
1560		return 0, 0, false
1561	case typeNChar:
1562		return 0, 0, false
1563	case typeGuid:
1564		return 0, 0, false
1565	case typeXml:
1566		return 0, 0, false
1567	case typeText:
1568		return 0, 0, false
1569	case typeNText:
1570		return 0, 0, false
1571	case typeImage:
1572		return 0, 0, false
1573	case typeVariant:
1574		return 0, 0, false
1575	case typeBigBinary:
1576		return 0, 0, false
1577	default:
1578		panic(fmt.Sprintf("not implemented makeGoLangTypePrecisionScale for type %d", ti.TypeId))
1579	}
1580}
1581